How to reuse a Button action - python

I am trying to reuse the action of this button, without recalling the command all over again, the thing is that, after the button executes the first "if" statement "y == 1".
Now, instead of having access to the second "if" statement "y == 2" (That is, assume the program starts now, if I enter 1 in the entry box and the button is clicked, the program should print "Yes!", then if I enter 2 again in the entry box and the button is clicked, the program should print "Yes!Yes!", but instead it starts the "def action()" all over again)
I want it to run like the second code if I use a console
from tkinter import *
win = Tk()
def action():
y = x.get()
if y == 1:
print("Yes!")
if y == 2:
print("Yes!Yes!")
elif y == 3:
print("Yes!Yes!Yes!")
else:
print("No")
x = IntVar()
e1 = Entry(win, textvariable = x).grid()
b1 = Button(win, text = "Button", command = action).grid()
win.mainloop()
The second code
y = eval(input("Enter a value: "))
if y == 1:
print("Yes")
y = eval(input("Enter a value: "))
if y == 2:
print("Yes!Yes!")
elif y == 3:
print("Yes!Yes!Yes!")
else:
print("No")

put
y = x.get()
clicked = False
after
b1 = Button(win, text = "Button", command = action).grid()
Now,
def action():
if y == 2 and clicked == True:
print("Yes!Yes!")
if y == 3 and clicked == True:
print("Yes!Yes!Yes!")
if y == 1 and clicked == False:
print("Yes!")
clicked = True
If I understood your question well, this might pop the desired result.

Walrus to rescued.
Code:
from tkinter import *
win = Tk()
def action():
# y = x.get()
if (y := x.get()) == 1:
print("Yes!")
elif y == 2:
txt= 'Yes!'
print(txt*2)
elif y == 3:
txt = 'Yes!'
print(txt*3)
else:
print("No")
x = IntVar()
e1 = Entry(win, textvariable = x).grid()
b1 = Button(win, text = "Button", command = action).grid()
win.mainloop()
Result:
Yes!
Yes!Yes!
Yes!Yes!Yes!
No

if I enter 1 in the entry box and the button is clicked, the program
should print "Yes!", then if I enter 2 again in the entry box and the
button is clicked, the program should print "Yes!Yes!", and so on.
Walrus to rescued.
Code:
from tkinter import *
win = Tk()
def action():
# y = x.get()
if (y := x.get()) == 1:
print("Yes!")
elif y == 2:
txt= 'Yes!'
print(txt*2)
elif y == 3:
txt = 'Yes!'
print(txt*3)
else:
print("No")
x = IntVar()
e1 = Entry(win, textvariable = x).grid()
b1 = Button(win, text = "Button", command = action).grid()
win.mainloop()
Result:
Yes!
Yes!Yes!
Yes!Yes!Yes!
No

Related

How to make a button with a command with the parameter/attribute of its name with tkinter?

How to make a button with a command with the parameter/attribute of its name with tkinter?
from tkinter import *
def openfile(name):
print(name)
for i in l:
if num == 2:
num = 0
y = y+100
x = 100
print(y)
print(x)
print(num)
bt = Button(second_frame, text=i, command=lambda: openfile(i)).grid(row=y, column=x, pady=10, padx=10)
num = num + 1
x = x + 100
print(num)
I want to set the button command to be open file then its name as an attribute. I don't know how to get the buttons name on the same line.
NOTE:
The button name differs from each button
You mean something like this ?
for i in range(5):
btn_name=str(i)
btn_obj=Button(second_frame,text=btn_name,command=lambda name=btn_name:openfile(name))

Tkinter Option menu and config

I am trying to make a GUI that have two dropdown menus and a text label.
The value selected in the first dropdown menu should update the list of options in the second dropdown menu. (this part of the code works correctly!).
Then, once the user select a value from the second dropdown menu the text label should update. I am trying to update the text label with a using the config method, but it does not seem to work. any ideas?
import tkinter as tk
from tkinter import *
root = Tk()
root.title("My app")
root.minsize(width=330,height=280)
options1 = ["Option 1","Option 2"]
options2 = [""]
options21 =["Option 1.1","Option 1.2","Option 1.3","Option 1.4"]
options22 = ["Option 2.1","Option 2.2","Option 2.3","Option 2.4"]
labelvuot=Label(root,text= " ")
def weigthtxt(event):
if om2.get() == "":
pass
else:
mydamage = int(om2.get().split(".")[1])
if mydamage == 1:
labelweigth.config(text="1")
elif mydamage == 2:
labelweigth.config(text="2")
elif mydamage == 3:
labelweigth.config(text="3")
elif mydamage == 4:
labelweigth.config(text="4")
else:
labelweigth.config(text="No number")
def add_option(self):
om2.set("")
labelweigth.config(text="")
answer = om1.get()
global options2
options2.clear()
if answer == "Option 1":
options2 = options2+options21
menu = drop2["menu"]
menu.delete(0, "end")
for x in options2:
menu.add_command(label=x,
command=lambda value=x: om2.set(value))
elif answer == "Option 2":
options2 = options2 + options22
menu = drop2["menu"]
menu.delete(0, "end")
for x in options2:
menu.add_command(label=x,
command=lambda value=x: om2.set(value))
def save():
element = om1.get()
damage = om2.get()
inten = r1.get()
exten = r2.get()
pergiu = r3.get()
txt = note.get(1.0,END)
print(element,damage,inten,exten,pergiu,txt,int(om2.get().split(".")[1]))
label1=Label(root,text= "Select Element").grid(row=1,column=3)
labelvuot.grid(row=1,column=5)
om1 = tk.StringVar()
om1.set("")
drop = tk.OptionMenu(root, om1, *options1, command= add_option)
drop.config(width=20)
drop.grid(row=1,column=7,columnspan=3)
label2=Label(root,text= "Damage Type").grid(row=2,column=3)
om2 = tk.StringVar()
om2.set("")
drop2 = tk.OptionMenu(root,om2, *options2,command=weigthtxt)
drop2.config(width=20)
drop2.grid(row=2,column=7,columnspan=3)
label3=Label(root,text= "Weigth").grid(row=3,column=1,columnspan=3)
labelweigth = Label(root,text="")
labelweigth.grid(row=3,column=7,columnspan=3)
root.mainloop()
tkinter module has an internal class _setit which is used by tk.OptionMenu class when setting up the menu actions.
You need to use this internal class when you populate the menu items inside add_option() function:
...
# it is executed when item of second dropdown menu is selected
def weigthtxt(value):
if value:
mydamage = int(value.split(".")[1])
if mydamage == 1:
labelweigth.config(text="1")
elif mydamage == 2:
labelweigth.config(text="2")
elif mydamage == 3:
labelweigth.config(text="3")
elif mydamage == 4:
labelweigth.config(text="4")
else:
labelweigth.config(text="No number")
def add_option(answer):
om2.set("")
labelweigth.config(text="")
options2.clear()
if answer == "Option 1":
options2.extend(options21)
elif answer == "Option 2":
options2.extend(options22)
menu = drop2["menu"]
menu.delete(0, "end")
for x in options2:
menu.add_command(label=x, command=tk._setit(om2, x, weigthtxt))
...

TKinter running through a loop

For a basic example, suppose I want to run a list of questions and for each question i want a button to be pressed which will append a value "yes" or "no" to the list.
window = tk.Tk()
app=tk.Frame(window)
app.grid()
response_list = []
y_button = tk.Button(app,text="yes", command=lambda x="yes": appendResponse(x))
n_button = tk.Button(app,text="no", command=lambda x="no": appendResponse(x))
questions=["q1","q2","q3"]
window.mainloop()
How can i make the window stay open and display all the questions until there is a complete list of answers?
You can write a function like the following:
#STARTS HERE
#Label with question
lbl1 = tk.Label(app, text="Are you a human?")
lbl1.grid()
def appendResponse(resp):
global response_list
questionNo = len(response_list)
if questionNo % 3 == 0:
lbl1.configure(text="Is this a valid question?")
elif questionNo % 3 == 1:
lbl1.configure(text="Is there a better way to do this?")
elif questionNo % 3 == 2:
lbl1.configure(text="Is this what you wanted to do?")
response_list.append(resp)
#FINISHES HERE

Python tkinter growing call stack?

So I'm making a program which calls a function to do some calculations, and there are buttons to press to change the inputs and recalculate.
It works great, except if a button is pressed before the calculations are finished, the new values are calculated and outputted before returning back to the previous values. Basically, the program does what I want, except it returns to the first calculations after button press and completing second calculations (all the variable values return).
A general schematic of the problem:
1. Root mainloop
2. Values inputted
3. Press 'Go'
4. Calculations printed to screen (Monty Carlo sim by the way)
5. Press button to change input values
6. New calculations printed to screen
7. Once new ones finish, calculations for old variable values return until completion
Is there a way to prevent python from returning to the previous variable values like this? My hope is that there is a way to return to the mainloop so that the calculations on the screen stay correct. Thanks!
Edit:
Here's the code (Sorry it's a bit long and this is my first time with tkinter):
from tkinter import *
from tkinter import ttk
from random import *
from statistics import *
from math import *
'''
Prompt user for: number attacking with, number of defenders at each space
Output: n approaching 100000 and error range approaching .3%, probabilities of next roll, probabilities of winning at each spot, average number of pieces lost & stddev,buttons for decreasing defender/attacker
'''
def reset():
attacker_entry.delete(0,END)
for i in range(len(spaces_entry)):
spaces_entry[i].delete(0,END)
update_buttons()
def update_buttons(*args):
buttons = [attacker_2,attacker_1,split_button,defender_1,defender_2]
try:
if int(attacker_entry.get()) > 1:
for button in buttons:
button['state'] = ['normal']
elif int(attacker_entry.get()) == 1:
attacker_2['state'] = ['disabled']
split_button['state'] = ['disabled']
elif int(attacker_entry.get()) == 0:
for button in buttons:
button['state'] = ['disabled']
return
if int(space1_entry.get()) > 1:
defender_2['state'] = ['normal']
elif int(space1_entry.get()) == 1:
defender_2['state'] = ['disabled']
split_button['state'] = ['disabled']
except:
for button in buttons:
button['state'] = ['disabled']
def subtract(label,*args):
if label == "both":
label = "att def 1"
end = int(label[-1:])
if "att" in label:
attacker_amount.set(int(attacker_entry.get()) - end)
if "def" in label:
space1.set(int(space1_entry.get()) - end)
if int(space1_entry.get()) == 0:
attacker_amount.set(int(attacker_entry.get()) - 1)
for i in range(len(spaces)):
try:
spaces[i].set(int(spaces_entry[i+1].get()))
except:
spaces[i].set("")
win_avgs[i].set("")
pieces_left[i].set("")
most_likely[i].set("")
space10.set("")
update_buttons()
go()
def check_if_multiple(list1,list2):
if len(list1)>1 and len(list2)>1:
ret_val = 2
else:
ret_val = 1
return ret_val
def set_rolls(total,limit):
list = []
for i in range(total):
if len(list) < limit:
list.append(randrange(1,7))
return list
def go(*args):
update_buttons()
try:
attacker_total = int(attacker_entry.get())
except:
return
defender_pieces_list = []
for entry in spaces_entry:
try:
new_val = int(entry.get())
if new_val == 0:
None
else:
defender_pieces_list.append(new_val)
except:
None
defender_total_spaces = len(defender_pieces_list)
attacker_total_original = attacker_total
total_trials = 10000
defender_losses = 0
attacker_losses = 0
first_round_defender_total_wins = 0
first_round_attacker_total_wins = 0
first_round_split_total = 0
space1_succ,space2_succ,space3_succ,space4_succ,space5_succ,space6_succ,space7_succ,space8_succ,space9_succ,space10_succ = [],[],[],[],[],[],[],[],[],[]
space1_all,space2_all,space3_all,space4_all,space5_all,space6_all,space7_all,space8_all,space9_all,space10_all = [],[],[],[],[],[],[],[],[],[]
succ_list = [space1_succ,space2_succ,space3_succ,space4_succ,space5_succ,space6_succ,space7_succ,space8_succ,space9_succ,space10_succ]
all_list = [space1_all,space2_all,space3_all,space4_all,space5_all,space6_all,space7_all,space8_all,space9_all,space10_all]
for trial in range(total_trials):
if trial%20 == 0:
for i in range(0,defender_total_spaces):
try:
win_avgs[i].set(round(((len(succ_list[i]))/trial)*100,1))
pieces_left[i].set(str(round(mean(all_list[i]),2)))
most_likely[i].set(mode(all_list[i]))
root.update()
except:
None
attacker_total = attacker_total_original
first_round = True
for i in range(defender_total_spaces):
defender_total = defender_pieces_list[i]
while defender_total>0 and attacker_total > 0:
defender_win = False
attacker_win = False
defender_rolls_list = set_rolls(defender_total,2)
attacker_rolls_list = set_rolls(attacker_total,3)
if len(attacker_rolls_list) == 1:
defender_rolls_list = [randrange(1,7)]
for j in range(check_if_multiple(defender_rolls_list,attacker_rolls_list)):
if max(defender_rolls_list)>=max(attacker_rolls_list):
attacker_total += -1
defender_win = True
else:
defender_total += -1
attacker_win = True
attacker_rolls_list.remove(max(attacker_rolls_list))
defender_rolls_list.remove(max(defender_rolls_list))
if first_round == True:
if defender_win == True and attacker_win == True:
first_round_split_total += 1
elif attacker_win == True:
first_round_attacker_total_wins += 1
elif defender_win == True:
first_round_defender_total_wins += 1
first_round = False
if defender_total == 0:
succ_list[i].append(attacker_total)
all_list[i].append(attacker_total)
if attacker_total == 1:
attacker_total == -1
if attacker_total == 0:
all_list[i].append(attacker_total)
attacker_total += -1
for i in range(0,defender_total_spaces):
try:
win_avgs[i].set(round(((len(succ_list[i]))/trial)*100,1))
pieces_left[i].set(str(round(mean(all_list[i]),2))+"("+str(round(stdev(all_list[i]),1))+")")
most_likely[i].set(mode(all_list[i]))
except:
None
height = 450
width = 600
shape = str(width) + "x" + str(height)
root = Tk()
root.title("Risk Probability Calculator")
root.geometry(shape)
content = ttk.Frame(root)
content.grid(column=0, row=0, sticky=(N, W, E, S))
content.columnconfigure(0, weight=1)
content.rowconfigure(0, weight=1)
title = ttk.Label(content, text="Risk Probability Calculator", relief="ridge", background="gray",font=("TkHeadingFont",20),anchor="center")
title.grid(column=1, row=1, columnspan=8, padx=3, pady=4,sticky=(N,W,E,S))
reset_button = ttk.Button(content, text="Reset", command=reset)
reset_button.grid(column=1, row=2,padx=3, pady=4, sticky=(N, W, E, S))
go_button = ttk.Button(content, text="Go", command=go)
go_button.grid(column=2, row=2,padx=3, pady=4, sticky=(N, W, E, S))
ttk.Label(content, text="Attacking with:").grid(column=1, row=3,padx=3, pady=4, sticky=(NW))
ttk.Label(content, text="Defending with:").grid(column=1, row=4,padx=3, pady=4, sticky=(NW))
for i in range(5,15):
text = "Space " + str(i-4) + ":"
ttk.Label(content, text=text).grid(column=1,padx=3, pady=4, row=i, sticky=(N,E,S))
attacker_amount = StringVar()
attacker_entry = ttk.Entry(content, textvariable=attacker_amount, width=4)
attacker_entry.grid(column=2, row=3,padx=3, pady=4, sticky=(N, W, S))
spaces = []
spaces_entry = []
for i in range(1, 11):
globals()['space'+str(i)] = StringVar()
spaces.append(globals()['space'+str(i)])
globals()['space'+str(i)+'_entry'] = ttk.Entry(content, textvariable=spaces[i-1], width=4)
globals()['space'+str(i)+'_entry'].grid(column=2, row=(i+4),padx=3, pady=4, sticky=(N, W, S))
spaces_entry.append(globals()['space'+str(i)+'_entry'])
attacker_2 = Button(content, text="Attacker -2",command=lambda: subtract("att 2"))
attacker_2.grid(column=4, row=2,padx=3, pady=4, sticky=(N,W,E,S))
attacker_1 = Button(content, text="Attacker -1",command=lambda: subtract("att 1"))
attacker_1.grid(column=5, row=2,padx=3, pady=4, sticky=(N,W,E,S))
split_button = Button(content, text="Split",command=lambda: subtract("both"))
split_button.grid(column=6, row=2,padx=3, pady=4, sticky=(N,W,E,S))
defender_1 = Button(content, text="Defender -1",command=lambda: subtract("def 1"))
defender_1.grid(column=7, row=2,padx=3, pady=4, sticky=(N,W,E,S))
defender_2 = Button(content, text="Defender -2",command=lambda: subtract("def 2"))
defender_2.grid(column=8, row=2,padx=3, pady=4, sticky=(N,W,E,S))
ttk.Separator(content,orient="vertical").grid(column=3,row=2,rowspan=15,padx=3, pady=4,sticky=(N,W,E,S))
results_frame = ttk.Labelframe(content, text='Results:')
results_frame.grid(column=4, row=3, columnspan=5, rowspan=12,padx=3, pady=4, sticky=(N,W,E,S))
pane = ttk.Panedwindow(results_frame, orient='horizontal')
pane.grid(column=1,row=1,columnspan=5,padx=3,sticky=(N,W,E,S))
pane1 = ttk.Labelframe(pane)
pane.add(pane1)
Label(pane1,text="% Win").grid(column=1,row=1,sticky=(N,W,E))
win_avgs = []
for i in range(1,11):
globals()['win_avg'+str(i)] = StringVar()
win_avgs.append(globals()['win_avg'+str(i)])
Label(pane1,textvariable=win_avgs[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S))
pane2 = ttk.Labelframe(pane)
pane.add(pane2)
Label(pane2,text="Pieces Left").grid(column=1,row=1,sticky=(N,W,E))
pieces_left = []
for i in range(1,11):
globals()['pieces_left'+str(i)] = StringVar()
pieces_left.append(globals()['pieces_left'+str(i)])
Label(pane2,textvariable=pieces_left[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S))
pane3 = ttk.Labelframe(pane)
pane.add(pane3)
Label(pane3,text="Most likely # of Pieces Left").grid(column=1,row=1,sticky=(N,W,E))
most_likely = []
for i in range(1,11):
globals()['most_likely'+str(i)] = StringVar()
most_likely.append(globals()['most_likely'+str(i)])
Label(pane3,textvariable=most_likely[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S))
root.mainloop()
The short answer is that it's because you call root.update(). This not only redraws the screen, but processes any pending events. A good rule of thumb is "never call update" for this exact reason. Infrequently you simply must, but usually there's a better way to organize your code. You can sometimes get away with it if you do it in a function that only takes a few ms, but it looks like your function computes a lot of things. If a user presses a key or clicks a button and then you call update, tkinter is going to try to process that event before continuing.
I would recommend first just removing the call and see what happens. If the screen seems to freeze (which it might, given how much code you're trying to run), you can try replacing it with root.update_idletasks(). That won't process any click or button events, only a certain class of event such as "repaint the screen".

Creating a Tkinter math Quiz

I am learning python and am having trouble getting this program to work correctly.
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25,1)
number2 = random.randrange(1,50,2)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if int(answer) != entryWidget.get().strip():
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions like the one below.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
answer = Questions()
Sub = lambda: Submit(answer, entryWidget)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
It just says "INCORRECT!" every time I push submit regardless of what I enter into the text box. Any suggestions would be appreciated. Thanks, Scott
Left side is an integer, right side is a string, so it's always False:
int(answer) != entryWidget.get().strip()
You can try:
int(answer) != int(entryWidget.get().strip())

Categories