The general idea of the code is that every one-and-a-half seconds, the text on the buttons changes randomly, so that each reads either ‘click’, ‘clack’ or ‘cluck’. If the player clicks a button labeled ‘click’, he or she scores 10 points. If the player clicks a button labeled ‘clack’ or ‘cluck’, he or she loses 10 points. When a button has been clicked, it changes color—to light green if the click scored points and to light yellow if it lost points. Clicking the same button again has no effect until the next time the button labels are changed, at which time the colors should also revert to gray.
The problem that I have is modifying the code so that each time the player scores 10 points the interval between label changes is reduced by 50 milliseconds and each time the player loses 10 points the interval is increased by 100 milliseconds.
Here is the original code, but I don't know how to modify the code for the intervals.
from tkinter import *
import random
score = 0
root = Tk()
scoreFrame = Frame(root)
scoreFrame.pack(expand=YES, fill=BOTH)
scoreLabel = Label(scoreFrame)
scoreLabel.pack(expand=YES)
def showScore():
scoreLabel['text'] = 'Score: {0}'.format(score)
clickFrame = Frame(root)
clickFrame.pack(side=BOTTOM, expand=YES, fill=BOTH)
def changeLabels():
for button in buttons:
button['text'] = random.choice(['click', 'clack', 'cluck'])
button['bg'] = buttonDefaultColor
root.after(1500, changeLabels)
def makeButton():
button = Button(clickFrame)
def cmd():
global score
if button['bg'] == buttonDefaultColor:
if button['text'] == 'click':
score += 10
button['bg'] = 'light green'
else:
score -= 10
button['bg'] = 'light yellow'
showScore()
button['command'] = cmd
button.pack(side=LEFT, expand=YES, fill=BOTH)
return button
buttons = [makeButton() for i in range(5)]
buttonDefaultColor = buttons[0]['bg']
changeLabels()
showScore()
You need to change the 1500 to either a global value or a class property. Something that can be updated.
Related
I just recently made a pomodoro clock implementation on python and I was facing some trouble with its execution but I came up with a solution for it but I observed a discrepancy in its execution.
So my whole code and implementation looks something like this (my code is not clean or pretty; sorry about that, I am one of those people who uses a mixture of tabs and spaces):
from tkinter import *
from time import *
from threading import Thread
# ---------------------------- CONSTANTS ------------------------------- #
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
FONT_NAME = "Courier"
WORK_MIN = 25
SHORT_BREAK_MIN = 5*60000
LONG_BREAK_MIN = 20*60000
class Reset:
def __init__(self):
self.click = False
self.activation = False
def button_command(self):
self.click = True
def timer_command(self):
return self.click
# ---------------------------- TIMER RESET ------------------------------- #
timer_reset = Reset()
reset = timer_reset.click
# ---------------------------- TIMER MECHANISM ------------------------------- #
def timer_mechanism():
minute=0
if counter[0]<60000:
if counter[0] % 1000 == 0 and counter[0]/1000<10:
canvas.itemconfig(clock_counter, text=(f"00:0{int(counter[0]/1000)}"))
canvas.update_idletasks()
elif counter[0]% 1000==0 and counter[0]/1000>=10:
canvas.itemconfig(clock_counter, text=(f"00:{int(counter[0] / 1000)}"))
canvas.update_idletasks()
elif counter[0]>=60000:
if counter[0]%1000==0:
transition=int(counter[0]/1000)
while transition>=60:
minute+=1
transition-=60
second=transition
if second<10 and minute<10:
canvas.itemconfig(clock_counter,text=(f"0{minute}:0{second}"))
canvas.update_idletasks()
elif second>=10 and minute<10:
canvas.itemconfig(clock_counter,text=(f"0{minute}:{second}"))
canvas.update_idletasks()
elif minute>=10 and second<10:
canvas.itemconfig(clock_counter, text=(f"{minute}:0{second}"))
canvas.update_idletasks()
else:
canvas.itemconfig(clock_counter,text=(f"{minute}:{second}"))
canvas.update_idletasks()
# -----------------------------New countdown mechanism----------------------------#
i = [4]
def start_countdown():
if not timer_reset.click and i[0] > 0:
# keep listening to the function that receives from the button while doing an after for the 25 min and 10 min respectively.3
timer.config(text="Work", fg=GREEN)
window.update_idletasks()
# the solution to this problem is to break up the after process instead of doing it all at the same time make use of small increments so that this after could finish withing a second or two and then go to another function that contains all the timer_reset.click values update and come everytime until we reach a limit somewhere probably an array value that will be updated until we get to the 25 minute mark so this insures as the signal from the button will be accepted.
execute("Work")
# start=time()
# end=time()
# while end-start<5:
# end=time()
# timer_reset.click=timer_reset.timer_command()
else:
window.destroy()
timer_reset.click = False
i[0] = 4
beginning()
def rest():
global start_time
start_time=0
timer_reset.activation = True
if not timer_reset.click:
global restloop
restloop = True
global workloop
workloop = False
timer.config(text="Break", fg=PINK)
if i[0] == 4:
global frame
frame = Frame(window, width=20, height=20)
frame.grid(row=3, column=1)
tick = Label(frame, text="✔", font=(FONT_NAME, 12, "bold"), bg=YELLOW, fg=GREEN)
tick.pack(side=LEFT)
window.update_idletasks()
if i[0] > 0:
execute("Break")
if timer_reset.click:
timer_reset.click = False
window.destroy()
beginning()
else:
window.destroy()
beginning()
else:
window.destroy()
i[0] = 4
timer_reset.click = False
beginning()
i[0] -= 1
counter=[0]
def execute(identifier):
if identifier=="Work":
window.after(1,mirror,LONG_BREAK_MIN)
if identifier=="Break":
window.after(1,mirror,SHORT_BREAK_MIN)
def mirror(value):
if timer_reset.click:
window.destroy()
i[0]=4
timer_reset.click=False
counter[0]=0
beginning()
elif counter[0]<value:
counter[0]+=1
timer_mechanism()
if value==LONG_BREAK_MIN:
execute("Work")
if value==SHORT_BREAK_MIN:
execute("Break")
elif value==LONG_BREAK_MIN:
counter[0]=0
window.deiconify()
window.attributes("-topmost",1)
window.after(300,window.attributes,"-topmost",0)
window.update()
rest()
elif value==SHORT_BREAK_MIN:
counter[0]=0
window.deiconify()
window.attributes("-topmost",1)
window.after(300,window.attributes,"-topmost",0)
window.update()
start_countdown()
# ---------------------------- UI SETUP ------------------------------- #
def beginning():
global window
window = Tk(className="Pomodoro")
window.title("Pomodoro")
window.config(pady=50, padx=100, bg=YELLOW)
window.wm_state("normal")
global timer
timer = Label(text="Timer", font=(FONT_NAME, 50, "bold"), bg=YELLOW, foreground=GREEN)
timer.grid(row=0, column=1)
global canvas
canvas = Canvas(width=200, height=223, bg=YELLOW, highlightthickness=0)
tomato = PhotoImage(file="tomato.png")
canvas.create_image(100, 100, image=tomato)
global clock_counter
clock_counter=canvas.create_text(100, 120, text="00:00", fill="white", font=(FONT_NAME, 35, "bold"))
canvas.grid(row=1, column=1)
start = Button(text="Start", highlightthickness=0, borderwidth=0, command=start_countdown)
start.grid(row=2, column=0)
end = Button(text="Reset", highlightthickness=0, borderwidth=0, command=timer_reset.button_command)
end.grid(row=2, column=2)
window.mainloop()
beginning()
And the UI part of my code looks something like this:
So the discrepnancy I was talking about was that after starting the program and the countdown is happening if by mistake or whatever reason the user presses the Start button again the countdown starts to happen faster and if you keep pressing the start button without hitting the reset button it starts counting down even faster and faster.
Now I think I understand why this might be but this is like a sliver of what the solution might be, I might be completely wrong for all I know but is it because of the after method since every time the user hits the button he is starting another thread of the after method process and this kind of creates a sense/illusion of multiprocessing(parallelism)? I really don't know, to be honest. I might be stretching too far, but please any type of explanation would really be helpful even if it is a jab at my answer. I am very genuinely curious as to why this is happening.
Any help/suggestion will be really helpful.
I'm trying to create a class that allows you to have a MenuBar that can be personalized in windows. It's nothing special since I'm new to coding. I'm trying different ways to change the background of the label behind the cascade buttons but I can only change the buttons ones.
from tkinter import *
TESTING = True
root = Tk()
root.attributes('-fullscreen',True)
class menubar():
"""You can use this to create a menu bar
There are some functions:
ButtonCascadeAdd: Lets you create a cascade button to which you will be able to add more buttons with
AddButtons function
AddButtons: just adds buttons to the cascades. you can chose cascades changing the input number from
0 to 9
Soon will be added color switch and others althought you can already do those things by yourself
since every btns[] object is a tkinter.Menubutton()"""
global labelframe
global contx
global btns
contx = 0
labelframe = LabelFrame(root)
btns = [Menubutton(labelframe) for i in range(10)]
def place(self, width = 300,height = 30,rely=0):
labelframe.place(width=width, height=height, rely=rely)
def ButtonCascadeAdd(self,text = "btns[",tearoff = 0):
"""Adds a cascade button.
You can pass in text to change the button title default is the name of the button in the code
so maybe it will prove useful to leave it like that for develop purpose.
You cant add a command to that from here.
If you need a button with a command and not a cascade look aat the FunctionButtonAdd function"""
global contx
if text == "btns[":
text = text+str(contx)+"]"
if contx == 10:
print("Max number of buttons exceeded the program will be stopped")
exit()
b = btns[contx]
b.config(text = text)
b.pack(side=LEFT)
b.menu = Menu(b, tearoff=tearoff)
b["menu"] = b.menu
labelframe.update()
contx += 1
print(contx)
def maincolor(self,bg = "light green",fg = "black",activebg = "green",activefg = "dark blue"):
global contx
for x in range(contx):
btns[x].config(bg=bg, fg=fg, activebackground=activebg, activeforeground=activefg)
btns[x].menu.config(bg = "black",fg = "white")
labelframe.config(bg=bg)
def doNothing():
print("Doing Nothing ^^")
if TESTING == True:
m = menubar()
m.place(width = 1980,height = 20)
m.ButtonCascadeAdd()
m.ButtonCascadeAdd()
btns[0].menu.add_command(label="test")
#print(dir(btns[0].menu))
m.maincolor()
root.mainloop()
I am a beginner in python and have designed a "Count the Colored Balls Game". I am now stuck at figuring out best way of restarting the game after one round is over.
Currently:
When you hit start game, it populates 25 random colored balls and then gives user 10 seconds to count red and green balls. It them shows the final answer as a messagebox. Once i dismiss the message box, the balls remain on screen and then when I hit start game, 25 more balls are piled on.
What I want:
How do I reset the game such that when I complete one round, and hit start game, it clears the existing game and restarts.
My Code
from tkinter import *
import random
import time
#from tkinter import ttk
from tkinter import messagebox
#creating a list of colors:
colors=["blue","red","yellow","green","red","pink","red","black","green","cyan"]
#creating global variables and inititializing:
global i
i=0
global redcount
redcount=0
global greencount
greencount=0
global canvas
def startgame():
global canvas
x=startclick()
if x==1:
time.sleep(5)
messagebox.showinfo("Answer"," number of red balls "+str(redcount)+
" and number of green balls is "+str(greencount))
#==============================================
def startclick():
global i
global canvas
global redcount
global greencount
for i in range(1,26):
m=random.randint(0,10)
if m == 1 or m ==4 or m==6:
redcount=redcount+1
if m == 3 or m==8:
greencount=greencount+1
try:
a=random.randint(50,250)
b=random.randint(50,350)
canvas.create_oval(a,b,a+50,b+50,outline="white",fill=colors[m],width=1)
canvas.update()
except:
print()
return(1)
#===============================================
#===============================================
root=Tk()
root.title("Count The Colors")
root.geometry("800x800+0+0") #dimension and position of main frame
#creating canvas of the game
canvas = Canvas(width=600,height=500, bg = "#d2b48c")
canvas.place(x=20, y=20)
w=Label(root,text="Can you count the number of red and green balls?",bg="black",fg="yellow")
w.place(x=30,y=500)
y=Label(root, text="You have 10 seconds to answer...press start to play",
bg="white", fg="black")
y.place(x=20,y=550)
b=Button(root,text = "Start", bg="#fd5f00", width=20, height=1,
font=("Times",12,"bold"), fg="brown", command = startgame)
b.place(x=20, y=600)
root.mainloop()
Appreciate some help on this
First you are not following up programming conventions but anyways you can clear canvas everytime your startclick() function is being called. Simply add canvas.delete("all") to delete the previously created ovals.
def startclick():
global i
global canvas
global redcount
global greencount
canvas.delete("all") #This is your solution
for i in range(1, 26):
m = random.randint(0, 10)
if m == 1 or m == 4 or m == 6:
redcount = redcount + 1
if m == 3 or m == 8:
greencount = greencount + 1
try:
a = random.randint(50, 250)
b = random.randint(50, 350)
canvas.create_oval(a, b, a + 50, b + 50, outline="white", fill=colors[m], width=1)
canvas.update()
except:
print()
return (1)
I'm making a game that finding seven right buttons(It has a fixed answer) among 12 buttons by using tkinter. There are a total of 12 buttons, and only if all seven of them are clicked will win the game.
I'm curious about how to make the window to see which button is activated or inactivated, and how to make a function to determine whether one wins or loses. (when seven specific buttons are activated, it wins.)
++
game1=tkinter.Tk()
game1.title("Test")
game1.geometry("600x450")
button1 = Button(game1, text=' 1 ', fg='black', bg='red',
height=3, width=10)
button1.place(x=0,y=300)
button2 = Button(game1, text=' 2 ', fg='black', bg='red',
height=3, width=10)
button2.place(x=100,y=300)
game1.mainloop()
This is the first time using tkinter on python so actually I stopped after writing this really basic code.
The player can choose seven buttons until player itself clicks the "finish" button. (after click that button, player cannot modify anything.)
At first, I thought if I declare "num" and +=1 on that when the right buttons are clicked, but this trial failed because the player can choose whether one activates or inactivates until until player itself clicks the "finish" button. So I thought that this code needs the way to check the final statements of the buttons.
Is there any ways to use something like "if" statements on tkinter? (if players choose right seven buttons, so it is found that they're activated --> then player wins.)
EDIT - I've updated the code:
import tkinter as tk
import tkinter.ttk as ttk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
from random import sample
tk.Tk.__init__(self, *args, **kwargs)
self.title("Buttons")
self.resizable(width=False, height=False)
row_count = 3
column_count = 4
self.winning_buttons_count = 7
assert 0 < self.winning_buttons_count <= row_count * column_count
winning_buttons_numbers = sample(range(0, row_count * column_count), k=self.winning_buttons_count)
self.selected_buttons_count = 0
self.selected_button_color = "gray"
self.correct_button_color = "green"
self.incorrect_button_color = "red"
self.missed_button_color = "orange"
self.default_button_color = tk.Button().cget("bg")
def on_press(button):
color = button.cget("bg")
if color == self.default_button_color and self.selected_buttons_count < self.winning_buttons_count:
button.configure(bg=self.selected_button_color)
button.configure(relief=tk.SUNKEN)
self.selected_buttons_count += 1
elif color == self.selected_button_color:
button.configure(bg=self.default_button_color)
button.configure(relief=tk.RAISED)
self.selected_buttons_count -= 1
def check_win():
selected_winning_count = 0
for button in self.buttons:
is_selected = button.cget("bg") == self.selected_button_color and \
button.cget("relief") == tk.SUNKEN
is_winning = button.number in winning_buttons_numbers
if is_selected:
if is_winning:
button.configure(bg=self.correct_button_color)
selected_winning_count += 1
else:
button.configure(bg=self.incorrect_button_color)
else:
if is_winning:
button.configure(bg=self.missed_button_color)
if selected_winning_count == self.winning_buttons_count:
self.finish_button.configure(text="You won!")
else:
self.finish_button.configure(text="Incorrect.")
self.buttons = []
for row in range(row_count):
for column in range(column_count):
button = tk.Button(self, text=" " * 8)
button.grid(row=row, column=column)
button.number = (row * column_count) + column
button.configure(command=lambda b=button: on_press(b))
self.buttons.append(button)
vertical_line = ttk.Separator(self, orient=tk.VERTICAL)
vertical_line.grid(row=0, column=column_count+1, rowspan=row_count, sticky="ns", padx=(8, 8))
self.finish_button = tk.Button(self, text="Did I win?", command=check_win)
self.finish_button.grid(row=row_count//2, column=column_count+2)
def main():
application = Application()
application.mainloop()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
I'm currently trying to use the entry widget in tkinter to get a number from the user, and then use that number to define a parameter of one of my other functions.
The code is very long, so I'll try summarize my thoughts after the block.
class NimGame():
def __init__(self, numberOfBalls):
self.numberOfBallsRemaining = numberOfBalls
print("Nim game initialized with {} balls.".format(self.numberOfBallsRemaining))
def remainingBalls(self):
return self.numberOfBallsRemaining
def take(self, numberOfBalls):
if (numberOfBalls < 1) or (numberOfBalls > 3) or (numberOfBalls > self.numberOfBallsRemaining):
print("You can't take that number of balls. Try again.")
# ## Update Label in the GUI to tell user they can't take that many balls.
# It might be better to "inactivate" the buttons that correspond to invalid number to take.
statusLabel.configure(text="You can't take that number of balls. Try again.")
else:
self.numberOfBallsRemaining = self.numberOfBallsRemaining - numberOfBalls
print("You took {} balls. {} remain.".format(numberOfBalls, self.numberOfBallsRemaining))
if self.numberOfBallsRemaining == 0:
print("Computer wins!")
else:
# ## After removing player-chosen balls, update graphics and then pause for 1.0 seconds
# before removing computer-chosen balls. This way the player can "see" the
# intermediate status. Perhaps think about a nicer way of showing this.
updateGraphics()
sleep(1.0)
computerMaxBalls = min(3, self.numberOfBallsRemaining)
compBallsTaken = random.randint(1,computerMaxBalls)
self.numberOfBallsRemaining = self.numberOfBallsRemaining - compBallsTaken
# ## After removing computer-chosen balls, update graphics again.
updateGraphics()
print("Computer took {} balls. {} remain.".format(compBallsTaken, self.numberOfBallsRemaining))
if self.numberOfBallsRemaining == 0:
print("You win!")
def updateGraphics():
canvas.delete('all')
centerX = leftmostBallXPosition
centerY = ballYPosition
for i in range(nimGame.remainingBalls()):
canvas.create_oval(centerX - halfBallSize,
centerY - halfBallSize,
centerX + halfBallSize,
centerY + halfBallSize,
fill="#9999ff")
centerX = centerX + spaceBetweenBalls + ballSize
canvas.update_idletasks()
def initializeNewGame():
numberOfBalls = e1.get()
initializeNimAndGUI(numberOfBalls)
def initializeNimAndGUI(numberOfBalls):
global nimGame
global ballSize, halfBallSize, spaceBetweenBalls, leftmostBallXPosition, ballYPosition
nimGame = NimGame(numberOfBalls)
canvas.delete('all')
ballSize = min(maxBallSize, int(((canvasWidth-canvasBorderBuffer)//numberOfBalls)/1.2))
halfBallSize = ballSize // 2
spaceBetweenBalls = int(0.2 * ballSize)
leftmostBallXPosition = (canvasBorderBuffer//2) + (spaceBetweenBalls//2) + halfBallSize
ballYPosition = canvasHeight // 2
updateGraphics()
def createGUI():
global rootWindow
global canvas
global statusLabel
global textEntry
global e1
rootWindow = Tk()
canvasAndButtons = Frame(rootWindow)
canvas = Canvas(canvasAndButtons, height=canvasHeight, width=canvasWidth, relief=SUNKEN, borderwidth=2)
canvas.pack(side=LEFT)
buttonframe = Frame(canvasAndButtons)
e1 = Entry(buttonframe)
e1.pack()
button1 = Button(buttonframe, text='Take 1', command=lambda:takeBalls(1))
button2 = Button(buttonframe, text='Take 2', command=lambda:takeBalls(2))
button3 = Button(buttonframe, text='Take 3', command=lambda:takeBalls(3))
button4 = Button(buttonframe, text='New Game', command=initializeNewGame)
button1.pack()
button2.pack()
button3.pack()
button4.pack()
buttonframe.pack(side=RIGHT)
canvasAndButtons.pack()
statusLabel = Label(rootWindow, text="Play Nim")
statusLabel.pack()
def runNim(numberOfBalls):
createGUI()
initializeNimAndGUI(numberOfBalls)
rootWindow.mainloop()
So to me it seems that the program is having issues updating the graphics when I do a second game. What should happen is that, for example, i call runNim(20) and play a game with 20 balls. After the game, I need to be able to enter a number in the entry widget, click new game, and have that be the new numberOfBalls. When I do that, I get the init message back stating "Nim game initialized with 10 balls." But the GUI doesnt change, no balls appear in the GUI, and if I try to take anything it gives traceback and errors.
I figured out my problem. When I was trying to convert the string from e1.get() into an integer, I wasn't accounting for the empty string when I first run the program. This gave me a ValueError: invalid literal for int() with base 10: ''. So I had to account for that, and now it works.