Countup method using Python (Tkinter) - python

I got my motivation from this post: Incerasing number by every second +1 in Tkinter label
So I decided to make a Scoreboard with Tkinter and I am about to pull my hair out because I know its a basic question with a most likely obvious answer, I just cant figure it out.
Its a football scoreboard. Comprised of 4 buttons
score_dict = {"Touchdown": 6, "Extra Point": 1, 'Field Goal': 3, "Conversion": 2, "Safety": 2}
Every time I hit the button I want the label to reflect the score but I cant figure out how to keep the previous amount of the label and add on to it.
So if the label reads 6 and I add a field goal it should read 10 instead of starting over again.
# Creating label + buttons and putting them on screen
label = Label(root, text=0)
buttons = [Button(root, text=i, command=lambda i=i: press(i)) for i in score_dict.keys()]
for i in range(len(buttons)):
buttons[i].grid(row=1, column=i)
label.grid(row=0, column=2)
# press function from button list comprehension:
def press(i):
global label
if score_dict[i] == 6:
if label['text'] < score_dict[i]:
label['text'] += 1
root.after(100, press, i)
if score_dict[i] == 1:
if label['text'] < score_dict[i]:
label['text'] += 1
root.after(100, press, i)
if score_dict[i] == 3:
if label['text'] < score_dict[i]:
label['text'] += 1
root.after(100, press, i)
if score_dict[i] == 2:
if label['text'] < score_dict[i]:
label['text'] += 1
root.after(100, press, i)
The problem is the if statement. When I press the button once, just as long as the score is more than the label reads it doesn't fit any of the conditions but I'm not sure how else to phrase it.
I posted this all over Reddit for 5 days with no answers and I'm ready to give up on it.

I've made necessary changes to function press. Code requires a working dictionary to keep track of score and a static dictionary to reset the testing statement.
Total score is in label.
import tkinter as tk
score_dict = {"Touchdown": 6, "Extra Point": 1,
"Field Goal": 3, "Conversion": 2,
"Safety": 2}
working_dict = score_dict.copy()
root = tk.Tk()
label = tk.Label(root, text = 0)
label.grid(sticky = tk.NSEW)
def press(i):
if working_dict[i] > 0:
working_dict[i] -= 1
label['text'] += 1
root.after(100, press, i)
else:
working_dict[i] = score_dict[i]
buttons = [tk.Button(root, text = i, command = lambda i = i: press(i)) for i in score_dict.keys()]
for i in range(len(buttons)):
buttons[i].grid(row = 1, column = i)
root.mainloop()

Related

How to create a keyboard from tkinter buttons that stores the entered letter?

I am writing a python hangman code with tkinter interactive window, which includes a keyboard. I have created the keyboard, however I cannot figure out how to find out which keyboard key was pressed by the user and how to store it as a letter in a variable. I will be really grateful for any help!
klavesnice = Tk()
klavesnice.geometry("800x700+120+100")
buttons = []
buttons = [
'q','w','e','r','t','y','u','i','o','p',
'a','s','d','f','g','h','j','k','l',
'z','x','c','v','b','n','m'
]
radek=3 #row
sloupec=0 #column
for button in buttons:
command=lambda x=button: select(x)
if button!='Space':
Button(klavesnice,text=button,width=5,font=("arial",14,"bold"),bg='powder blue',command=command,padx=3.5,pady=3.5,bd=5).grid(row=radek,column=sloupec)
if button=='Space':
Button(klavesnice,text=button,command=command).grid(row=5,column=sloupec)
sloupec+=1
#určení rozložení klávesnice
if sloupec>9 and radek==3:
sloupec=0
radek+=1
if sloupec>8 and radek==4:
sloupec=0
radek+=1
The code above is what displays the keyboard and the code below is the only thing I was able to come up with, which does not save the clicked key to a variable.
zadane=""
entry=Text(zadane_rm,width=43,height=3)
entry.grid(row=1,columnspan=40)
def select(value):
if value=='Space':
entry.insert(END,'')
else:
entry.insert(END, value)
I would like to store the clicked letter in a string variable called zadane.
To do what you want only requires modifying the select() function so it appends the current value argument to the global zadane string variable. Note I have reformatted your code to follow the PEP 8 - Style Guide for Python Code guidelines more closely to make it more readable.
import tkinter as tk # Avoid `import *`
klavesnice = tk.Tk()
klavesnice.geometry("800x700+120+100")
buttons = [
'q','w','e','r','t','y','u','i','o','p',
'a','s','d','f','g','h','j','k','l',
'z','x','c','v','b','n','m'
]
zadane = ''
entry = tk.Text(klavesnice, width=43, height=3)
entry.grid(row=1, columnspan=40)
def select(value):
global zadane
if value == 'Space':
entry.insert('end', ' ')
else:
entry.insert('end', value)
zadane = zadane + value
print(f'{zadane=!r}')
radek = 3 #row
sloupec = 0 #column
for button in buttons:
command = lambda x=button: select(x)
if button != 'Space':
tk.Button(klavesnice, text=button, width=5, font=("arial", 14, "bold"),
bg='powder blue', command=command, padx=3.5, pady=3.5, bd=5
).grid(row=radek, column=sloupec)
if button == 'Space':
tk.Button(klavesnice, text=button, command=command).grid(row=5, column=sloupec)
sloupec += 1
# Specify the keyboard layout
if sloupec > 9 and radek == 3:
sloupec = 0
radek += 1
if sloupec > 8 and radek == 4:
sloupec = 0
radek += 1
klavesnice.mainloop()

tkinter: checkbox doesn't update in for-loop [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 1 year ago.
I'm stuck on the following problem. With a for-loop, I want to make a few checkboxes that automatically update a label stating whether the checkbox is ticked or not. However, it gives the wrong results (it always says that the checkboxes are ticked, whether this is the case or not; noteworthy is the fact that the checkboxes are unticked by default), see here how the GUI looks like (including error). The IntVars corresponding with the checkboxes are working correctly, as can be seen when ticking at least one of the checkboxes and pressing a button whose function is to read the checkboxes. See also the following code:
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(i): # update label saying if checkboxes are ticked
if checkbox_var[i].get == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes(i))
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()
Could somebody help me with updating the labels? If there is another way to fix this issue, e.g. with buttons to be pressed instead of checkbuttons to be ticked, that would also work for mee.
i is always 2 because you're actually not running any loop after mainloop is started.
The following kind of works but you need to change something about the labels, because right now all labels are just added on top of each other. You should create them once and then just update the text but I'll leave that part for you.
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(): # update label saying if checkboxes are ticked
for i in range(n_passes):
if checkbox_var[i].get() == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
print(i)
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes)
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()

'Event' object is not subscriptable

I am trying to write a tic-tac-toe in Python but I get this error: 'Event' object is not subscriptable
The general idea is that when a button is pressed, if it doesn't have a text, it will change it's text in an "X" or "O" depending on the turn.
But I am stuck due to this error.
I have not much experience with Python so I need a fix easy to understand and implement. Thanks!
Code:
from tkinter import *
window = Tk()
btn = [None] * 9
btn_id = [None] * 9
#position of button array
def BTNposition():
i = 0
c = 0
k = 0
while i < 9:
#declaration of button array
btn[i] = Button(window, text = "", height = 10, width = 20, borderwidth = 5, command = lambda i=i: GAME)
btn[i].place(x= c, y= k)
btn_id[i] = btn[i]
print(btn[i], btn_id[i])
i+= 1
if c == 300:
k += 150
c = 0
else:
c += 150
BTNposition()
def GAME(btn):
turn = 0
if btn["text"] == "" and turn % 2 == 0: #here the error
btn.config(text = "X")
turn += 1
elif btn["text"] == "" and turn % 2 == 1:
btn.config(text = "O")
turn += 1
i = 0
#while i < 9:
#btn[i].bind("<Button 1>", GAME)
#find button pressed
window.bind("<Button 1>", GAME)
#print(click_position.btnp_x, click_position.btnp_y)
window.title('PyTris')
window.geometry("700x450")
window.mainloop()
I will update the post whenever I do major changes to the code.
Several problems:
window.bind("<Button 1>", GAME) a useless button that calls to GAME without providing a parameter hence it getting provided the default ButtonPressEvent as parameter which GAME is indexing into wich leads to the reported error
no exact button placement although you calculate positions
confused usages of = vs == inside GAME function
use of global variables with danger of confusing global and local identically named ones
variable names reused (or not used at all in case of the lambda i)
Fixing your code with minimalistic changes to it:
from tkinter import *
window = Tk()
btn = [None] * 9
turn = 0
#position of button array
def BTNposition():
c, k = 0, 0
for i in range(9):
# put button in array, callback is provided with the buttons index
# in the global array holding all the buttons
btn[i] = Button(window, text="", height=10, width=20, borderwidth=5,
command= lambda idx=i: GAME(idx))
# fix button on coordinates
btn[i].place(x=c, y=k)
if c == 300:
k += 150
c = 0
else:
c += 150
# btn_nr is supposed to be an index into the global btn-array holding your buttons
def GAME(btn_nr):
global turn # turn count is held globally, we want to modify it
button = btn[btn_nr] # get the button we are at
# only allow modification on buttons that are not yet X or O
if button["text"] == "":
# place the correct marker and advance turns
button["text"] = "X" if turn % 2 == 0 else "O"
turn += 1
BTNposition()
window.title('PyTris')
window.geometry("700x450")
window.mainloop()

How to see which button is activated / determine right buttons are activated on python tkinter

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())

Python tkinter: Sorting the contents of an OptionMenu widget

Hello everyone and thanks in advance!
I've searched all around google and read almost every result i got and i still can't figure
it out, so please at least point me at some direction!
I read about pmw but i want to see if there is any way to do it with tkinter first.
I'm writing a simple enough program for DnD dice rolls and i have an OptionMenu
containing some of the dice someone needs to play. I also have an input field for entering
a die that is not included in my default options. My problem is that even though the new
option is added successfully, the options are not sorted.
I solved it at some point by destroying the OptionMenu when the new option was added,
sorting my List and then rebuilding the OptionMenu from scratch, but i was using the
place manager method at that time and i had to rewrite the program later because i had
some resolution problems. I'm using the pack manager now and destroying/rebuilding
is not an option unless i want to "re"pack all my widgets or make exclusive labels for them!
Here is a working sample of my code:
from tkinter import *
class DropdownExample(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.pack(fill = 'both', expand = True)
# Add Option Button
self.addOptBtn = Button(self, text = "Add Option", command = self.add_option)
# Option Input Field
self.newOpt = IntVar()
self.newOpt.set("Type a number")
self.optIn = Entry(self)
self.optIn['textvariable'] = self.newOpt
# Dropdown Menu
self.myOptions = [0, 1, 2]
self.selOpt = IntVar()
self.selOpt.set("Options")
self.optMenu = OptionMenu(self, self.selOpt, *self.myOptions)
# Positioning
self.addOptBtn.pack(side = 'left', padx = 5)
self.optIn.pack(side = 'left', padx = 5)
self.optMenu.pack(side = 'left', padx = 5)
def add_option(self):
self.numToAdd = ""
self.counter = 0
try:
self.numToAdd = int(self.optIn.get()) # Integer validation
while self.counter < len(self.myOptions): # Comparison loop & error handling
if self.numToAdd == self.myOptions[self.counter]:
print("Already exists!")
break;
elif self.numToAdd < 0:
print("No less than 0!")
break;
elif self.counter < len(self.myOptions)-1:
self.counter += 1
else: # Dropdown menu option addition
self.myOptions.append(self.numToAdd)
self.myOptions.sort()
self.optMenu['menu'].add_command(label = self.numToAdd)
self.selOpt.set(self.numToAdd)
print("Added succesfully!")
self.counter += 2
except ValueError:
print("Type ONLY numbers!")
def runme():
app = DropdownExample()
app.master.title("Dropdown Menu Example")
app.master.resizable(0, 0)
app.mainloop()
runme()
I am using Python 3.3 on Windows 7
There is a set of insert_something() methods in Menu. You must keep your list sorted with each insert (bisect module).
from tkinter import *
import bisect
...
else: # Dropdown menu option addition
index = bisect.bisect(self.myOptions, self.numToAdd)
self.myOptions.insert(index, self.numToAdd)
self.optMenu['menu'].insert_command(index, label=self.numToAdd)
self.selOpt.set(self.numToAdd)
print("Added succesfully!", self.myOptions)
self.counter += 2
Replace the line:
self.optMenu['menu'].add_command(label = self.numToAdd)
with:
for dit in self.myOptions:
self.optMenu['menu'].delete(0)
for dat in self.myOptions:
self.optMenu['menu'].add_command(label = dat)
The gotcha is that "add_command" takes the item to add to the menu, while "delete" takes the index of the item.
It seems that whatever way i choose to follow on this one, it all comes down to updating
the widget.
Updating a frame usually redraws a portion or the whole frame if needed.
So i went back to square one. I destroyed the widget, updated the list and then created it again.
As for the position, i used a label as a background only for the OptionMenu.
That way i can delete/replace my OptionMenu as i please, without moving any widgets around, as long as it stays inside it's label and it's the only one in there and of course as long as i don't move any labels.
This probably is a workaround, not a solution, but it get's the job done and with a bit
of optimization it can be used for any other widget having the same problem.
from tkinter import *
class DropdownExample(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.pack(fill = 'both', expand = True)
# Add Option Button
self.addOptBtn = Button(self, text = "Add Option", command = self.add_option)
# Option Input Field
self.newOpt = IntVar()
self.newOpt.set("Type a number")
self.optIn = Entry(self)
self.optIn['textvariable'] = self.newOpt
# Dropdown Menu
# menu's label
self.optMenuLabel = Label(self)
# option menu
self.myOptions = [0, 1, 2]
self.selOpt = IntVar()
self.selOpt.set("Options")
self.optMenu = OptionMenu(self.optMenuLabel, self.selOpt, *self.myOptions)
# Positioning
self.addOptBtn.pack(side = 'left', padx = 5)
self.optIn.pack(side = 'left', padx = 5)
self.optMenuLabel.pack(side = 'left', padx = 5)
self.optMenu.pack(side = 'left', padx = 5)
def add_option(self):
self.numToAdd = ""
self.counter = 0
try:
self.numToAdd = int(self.optIn.get()) # Integer validation
while self.counter < len(self.myOptions): # Comparison loop & error handling
if self.numToAdd == self.myOptions[self.counter]:
print("Already exists!")
break;
elif self.numToAdd < 0:
print("No less than 0!")
break;
elif self.counter < len(self.myOptions)-1:
self.counter += 1
else: # Dropdown menu option addition
self.myOptions.append(self.numToAdd)
self.myOptions.sort()
self.selOpt.set(self.numToAdd)
self.optMenu.destroy()
self.optMenu = OptionMenu(self.optMenuLabel, self.selOpt, *self.myOptions)
self.optMenu.pack(side = 'left', padx = 5)
print("Added succesfully!", self.myOptions)
break;
except ValueError:
print("Type ONLY numbers!")
def runme():
app = DropdownExample()
app.master.title("Dropdown Menu Example")
app.master.resizable(0, 0)
app.mainloop()
runme()

Categories

Resources