I want to make Button2 do something, but only if Button1 has been pressed first and it's code was successfully run.
Also: Button2 should not execute button_1's function, and I do not want to use global variables.
The code below was my initial thought, and it did not work. I've searched for the right way, but neither of the methods I found gave me the result I hoped for.
Can anyone tell me how to correct this? I'm also open for easier or better ways to achieve my goal.
import tkinter as tk
from sys import exit
window = tk.Tk()
def button_1():
print("Button 1 pressed")
button_1_pressed = "Yes"
return button_1_pressed
def button_2():
if (button_1_pressed == "Yes"):
print("Button 1 was pressed, taking action")
# Action goes here
else :
print("Button 1 was NOT pressed, no action is done")
btn_1 = tk.Button(master=window, text="Button 1", width=10, height=2, command=button_1)
btn_1.pack()
btn_2 = tk.Button(master=window, text="Button 2", width=10, height=2, command=button_2)
btn_2.pack()
btn_Close = tk.Button(master=window, text="Close", width=10, height=2, command=exit)
btn_Close.pack()
window.mainloop()
Note: This is just a quick and simple script, illustrating exactly what I need help with in all simplicity.
How to pass variable from one function to another (button pressed)
To get returned value from the callback you should use invoke() method of the Button.
BUT it's just returned value, and unfortunately you cannot use it as a flag, as it doesn't track was the button pressed or not.
So the trick is to create your custom button with a flag which will be changed to True by callback and pass the flag as an argument to the button_2, to do so you can use lambda or partial func.
I hope it's fine for you, despite of it uses the vars out of function scope.
Updated code:
import tkinter as tk
from sys import exit
window = tk.Tk()
class MyButton(tk.Button):
pressed = False
def button_1():
print("Button 1 pressed")
button_1_pressed = "Yes"
btn_1.pressed = True
return button_1_pressed
btn_1 = MyButton(master=window, text="Button 1", width=10, height=2, command=button_1)
btn_1.pack()
def button_2(state):
if state:
print("Button 1 was pressed, taking action")
print('gotcha!')
else:
print("Button 1 was NOT pressed, no action is done")
btn_2 = tk.Button(master=window, text="Button 2", width=10, height=2, command=lambda: button_2(btn_1.pressed))
btn_2.pack()
btn_Close = tk.Button(master=window, text="Close", width=10, height=2, command=exit)
btn_Close.pack()
window.mainloop()
Useful links:
https://www.tutorialspoint.com/python/tk_button.htm
How to pass arguments to a Button command in Tkinter?
Related
Using Tkinter and Python. Already created a window for the buttons to be placed on. I want there to be four buttons to appear, and I want to be able to click one of the four buttons, and be able for it to set the selection variable = "whatever I clicked", so that I can then use this variable later to call an API. When I run the program and click on the "General knowledge" button and print the selection, it does correctly print "General knowledge", but then when I try to return this selection variable it just doesn't work and I don't know why.
def select1():
selection = "General Knowledge"
print(selection)
def select2():
selection = "Science"
def select3():
selection = "Entertainment"
def select4():
selection = "Miscellaneous"
button1 = tk.Button(text = "General Knowledge", command = select1)
button1.place(x=100, y=100)
button2 = tk.Button(text = "Science", command = select2)
button2.place(x=100, y=140)
button3 = tk.Button(text = "Entertainment", command = select3)
button3.place(x=100, y=180)
button4 = tk.Button(text = "Miscellaneous", command = select4)
button4.place(x=100, y=220)
There are several ways to accomplish your goal.
One way is to write a single function that will take a value to assign to your variable. This way you can have as many buttons as you like and only a single function.
Not if you are using functions you have to either pass the variable to the function or let the function know it is in the global namespace.
import tkinter as tk
root = tk.Tk()
selection = ''
def assign_value(value):
global selection
selection = value
lbl["text"] = value
print(selection)
lbl = tk.Label(root, text='Selection Goes Here')
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: assign_value("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: assign_value("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: assign_value("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: assign_value("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
Or you can assign the value directly from the button.
import tkinter as tk
root = tk.Tk()
selection = tk.StringVar()
selection.set('Selection Goes Here')
lbl = tk.Label(root, textvariable=selection)
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: selection.set("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: selection.set("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: selection.set("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: selection.set("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
I am sure if I spent more time on this I could think up something else but the idea is basically write your code in a more DRY (Don't Repeat Yourself) fashion and make sure you are assigning the value to the variable in the global namespace or else it will not work as you expect.
I just new for the GUI and need little help.
a=int(input())
if a==0:
print("hi")
else:
print("hello")
I want to change input process to click button, like a switch.
left button -> a=0
right button -> a=1
window=tkinter.Tk()
window.title("")
window.geometry("640x640+100+100")
window.resizable(True, True)
a=tkinter.Button(window, text="left")
a.pack()
b=tkinter.Button(window, text="right")
b.pack()
window.mainloop()
I can see left, right button but I don't know how to put values.
Is there any example I can use?
Thanks
Does this example help You:
from tkinter import Tk, Button
def switch(btn1, btn2):
btn1.config(state='disabled')
btn2.config(state='normal')
print(btn1['text'])
window = Tk()
window.title("")
on = Button(window, text="On", command=lambda: switch(on, off))
on.pack(side='left', expand=True, fill='x')
off = Button(window, text="Off", command=lambda: switch(off, on))
off.pack(side='left', expand=True, fill='x')
off.config(state='disabled')
window.mainloop()
If You have questions ask but here is pretty good site to look up tkinter widgets and what they do, their attributes.
Also I suggest You follow PEP 8
You need to add a function to each one that will be executed when the buttons are clicked like this:
import tkinter as tk
def left_clicked():
print("Left button clicked")
right_button.config(state="normal") # Reset the button as normal
left_button.config(state="disabled") # Disable the button
def right_clicked():
print("Right button clicked")
right_button.config(state="disabled")
left_button.config(state="normal")
window = tk.Tk()
window.title("")
window.geometry("640x640+100+100")
# window.resizable(True, True) # Unneeded as it is already the default
left_button = tk.Button(window, text="left", command=left_clicked)
left_button.pack(side="left")
right_button = tk.Button(window, text="right", command=right_clicked,
state="disabled")
right_button.pack(side="right")
window.mainloop()
I'm currently writing a Python Tkinter START and STOP button.
As it uses tkinter when I click START the STOP button should appear in it's place. But to do this I need to use .destroy() on the button. So to get around this I've done the following (see code blow); however it seems bulky and can't but feel I've over complicated it. Any suggestions would be great
def stop():
global start_button
try:
stop_button.destroy()
except NameError:
pass
print("Stopped. Hit GO to go again!")
start_button = Button(self.b, text="GO!", font="calibri, 18", command=started, fg="white", width=10)
start_button.pack(side=BOTTOM)
start_button.config(bg="green")
def started():
global stop_button
try:
start_button.destroy()
except NameError:
pass
print("Started. Hit ENTER to Stop!")
stop_button = Button(self.b, text="STOP!", font="calibri, 18", command=stop, fg="white", width=10)
stop_button.pack(side=BOTTOM)
stop_button.config(bg="red")
def first_start():
start.destroy()
started()
start = Button(self.b, text="START!", font="calibri, 18", command=first_start, fg="white", width=10)
start.pack(side=BOTTOM)
start.config(bg="green")
Here is a minimalist start/stop button that toggles its aspect and behavior when clicked. There is no need to destroy and replace buttons with such a toggling mechanism.
import tkinter as tk
def do_the_start_things():
# replace print with the things to do at start
print('starting now')
def do_the_stop_things():
# replace print with the things to do at stop
print('stopped!')
def toggle_start_stop():
if startstop['text'] == 'START':
startstop.config(text='STOP', fg='red')
do_the_start_things()
else:
startstop.config(text='START', fg='green')
do_the_stop_things()
root = tk.Tk()
startstop = tk.Button(root, text='START', command=toggle_start_stop, fg='green')
startstop.pack()
root.mainloop()
Recently I was working on a program where when one clicked a button, it would delete all of the tkinter buttons they made through a .yml file. Here is an example of what I mean:
(All TKinter Root Init Here)
button1 = Button(root, text="hi")
button2 = Button(root, text="hi again")
button3 = Button(root, text="hi again again")
button4 = Button(root, text="OK this is getting tiring")
button5 = Button(root, text="go away")
button6 = Button(root, text="...")
def del_all():
for i in range(999999999):
button(i).place_forget() #I was hoping to make button(i) give the output button1, then button2, and so on.
root.mainloop()
Try nametowidget in tkinter,example like:
import tkinter as tk
r = tk.Tk()
for i in range(5):
tk.Button(r,text=i).pack()
r.nametowidget(".!button").pack_forget()
r.mainloop()
This will remove the first button.If you want to remove the second button, you need to use r.nametowidget(".!button2").pack_forget()
So for you code,you may need to use:
def del_all():
root.nametowidget(".!button").place_forget()
for i in range(2, 999999999):
root.nametowidget(".!button"+str(i)).place_forget()
About the parameter in the nametowidget, there is a clear description.
You could also use winfo_children and use .widgetName to check whether it is a button,like:
import tkinter as tk
r = tk.Tk()
tk.Label(r, text="test").pack()
for i in range(5):
tk.Button(r,text=i).pack()
for i in r.winfo_children():
if i.widgetName == 'button':
i.pack_forget()
r.mainloop()
The solution would depend on how the buttons are named/stored.
For example, if the buttons were a list. Something like:
buttons = ['button1', 'button2', 'button3', 'button4']
Then you an delete by calling:
buttons.remove()
And that would 'clear' the list.
Am trying to make GUI app which compulsory you have to select one of predict button before the number entered will be printed to the terminal,if none of predictbutton is selected the should print outselect predict button to proceed.
In pseudecode something like:
def check:
now = new.get()
if no lotto_button is selected:
print("select predict button to proceed")
else:
print(now)
But having challenges:
1:when i select one predict button both buttons raised.
2:How to make the predict compulsory to be selected before the content in the entry will be printed.
import tkinter as tk
def terminal():
now = new.get()
print(now)
def start_func():
lotto_button.configure(relief=tk.SUNKEN, state=tk.DISABLED)
lotto_button1.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
lotto_button = tk.Button(root, text="predict one", command=start_func)
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two", command=start_func)
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[stop_func(),
terminal()]).place(x=150, y=300)
root.mainloop()
Thank you and your advice to do is welcome.
As for making it compulsory for picking, you can define a flag in outermost scope (in same level as root = tk.Tk()) so that you can see in your functions if it's set or not like:
isPredicted = False
And as for disabling each button when one is picked, you can define your your start_func such that it takes button object (lotto_button or lotto_button1) as argument:
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
To be able to use this function, you need to configure your buttons in the following way, so that they pass themselves as the argument:
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
You should have isPredicted flag in your stop_func as well so that it unsets it:
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
As for your terminal function, you'd want to act based on the state of isPredicted so it needs to be defined as:
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
finally in your "print number" button you need to swap the order of the functions in lambda or isPredicted is always False as far as that button's command is concerned:
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
Your final code should look like:
import tkinter as tk
from tkinter import messagebox
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
isPredicted = False
lotto_button = tk.Button(root, text="predict one")
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two")
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
root.mainloop()
When you're clicking on one of the button prediction, both are raised because in your function start_func, you're configuring both.
Instead of configuring both of them you can bind an event click and getting the widget in start_func like this:
lotto_button = tk.Button(root, text="predict one")
lotto_button.bind('<1>', start_func)
lotto_button.pack(side="left")
And then in your start_func :
def start_func(event):
w = event.widget
w.configure(relief=tk.SUNKEN, state=tk.DISABLED)
About your second point, I'm not sure to understand what you mean.
Using Radiobutton widgets tends to be better for this sort of multiple choice processing.
Radiobuttons belong to "groups" which means that you can set them up so that one always needs to be selected by default. This means that you don't need to have any kind of error catching or display any sort of instruction to the user, it just intuitively works.
from tkinter import *
root = Tk()
def command(v, entry):
print(v.get(), entry.get())
v = StringVar()
v.set(1)
entry = Entry(root)
rb1 = Radiobutton(root, text="Predict One", variable=v, value=1, indicatoron=0)
rb2 = Radiobutton(root, text="Predict Two", variable=v, value=2, indicatoron=0)
button = Button(root, text="Print Number", command=lambda:command(v, entry))
entry.pack()
rb1.pack()
rb2.pack()
button.pack()
root.mainloop()
So we create a StringVar() which we use to define which Radiobutton widgets should be linked together and then we set it's value to 1 which is the value of the "Predict One" button. If the user presses the other Radiobutton then the value changes to 2 which means the first button "unpresses" and the value of the StringVar() is changed to 2.