I want to ask that if I click on a button, then it perform a command and if I click again on the button then it perform another command. Basically I have two commands which I want to use in loop.
#Import tkinter here
from tkinter import *
#defining root function.
root = Tk()
root.geometry('200x100')
#define fuction for labelA
def funcA():
labelA["text"] = "A responds"
#define fuction for labelB
def funcB():
labelB["text"] = "B responds"
#Define button.
button = Button(root, text = 'Click Me', command=lambda:[funcA(), funcB()])
button.pack()
#creating both label A and B
labelA = Label(root, text="A")
labelB = Label(root, text="B")
labelA.pack()
labelB.pack()
root.mainloop()
In this code when I click on button, both the function run at same time. But I want that when i click on the button, the first function should run and if I click again on button then run second function. This will be in loop (like first of all first label will update then second label will update then again first label update then again second label).
You should have a bool value tracking if the button has been pressed or not. You can change this value in your functions as well.
somebool = False
#define fuction for labelA
def funcA():
if somebool:
labelA["text"] = "A responds"
#define fuction for labelB
def funcB():
if !somebool:
labelB["text"] = "B responds"
Note that this approach is not good if you want to access one function alone from another button. If you have a bool state like this though, you do not need 2 separate functions. You can make an event handler for the button and then call funcA or funcB from there.
somebool = False
def handler():
funcA() if somebool else funcB()
def funcA():
labelA["text"] = "A responds"
def funcB():
labelB["text"] = "B responds"
button = Button(root, text = 'Click Me', command=handler)
If you don't care about reusing the functions, change the command attribute for the button in your function to run the other one.
IIUC you want to alternate between two (or more) functions when clicking a button. So you can use itertools.cycle (built-in) to create an iterable that will loop forever over the given items in a tuple or list or sth else. So you add the two functions to the cycle and the button calls a third function that just gets the next item in the cycle and calls it and so on. (also I used just one label so that change is always visible since in your case you wouldn't see any change, but I believe you can adapt these functions for your needs):
import tkinter as tk
import itertools
def func_a():
label.config(text='a responds')
def func_b():
label.config(text='b responds')
toggle_funcs = itertools.cycle((func_a, func_b))
def toggle():
func = next(toggle_funcs)
func()
root = tk.Tk()
label = tk.Label(root, text='None')
label.pack()
btn = tk.Button(root, text='Click Me', command=toggle)
btn.pack()
root.mainloop()
Also:
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Have two blank lines around function and class declarations. Object method definitions have one blank line around them.
i think you can save the button inside a variable and when function1 run after execution set command attribute to function2 and after function2 executed set command to function1
Related
I'm trying to make a button that saves your username but then goes away after you set it.
this is my code:
def printValue():
User = Name.player_name.get()
label.config(text=f'Hi, {User}')
Name.button.destroy()
Name.player_name.destroy()
def Name():
label.config(text="What's your name?")
Name.player_name = Entry(root)
Name.player_name.pack(pady=15)
Name.button = Button(text="Change", command=printValue)
Name.button.pack()
The code below, with some minor changes like enabling change with [Return] and some layout cosmetics works OK (also with un-commented lines in printValue) . If you want the [Change] button and the entry area to go away un-comment the two lines turned into comments in the printValue function:
# https://stackoverflow.com/questions/72671126/tkinter-destroying-an-object-in-a-different-function-isnt-working
from tkinter import Tk, mainloop, Entry, Button, Label
root = Tk()
label = Label(root, font=('',12), padx=15, pady=5)
label.pack()
def Name():
label.config(text="What's your name?")
Name.player_name = Entry(root, font=('',12))
Name.player_name.pack(padx=15, pady=15)
Name.player_name.focus()
Name.button = Button(text="Change", command=printValue)
Name.button.pack()
def printValue(event=None):
User = Name.player_name.get()
# Name.player_name.destroy()
# Name.button.destroy()
label.config(text=f'Hi, {User}')
Name()
root.bind("<Return>", printValue)
mainloop()
By the way: The in the question provided code demonstrates an interesting approach of making names of variables global by setting function attributes in the function itself. This way it is possible to assign values in one function and retrieve them in another without passing return values or declaring variables global. I am not aware of already having seen such approach used in Python code here on stackoverflow. How does it come you use such code?
textvarible that is created in click function for entry box is not printing any thing in function d. i.e on call to function d(), a.get() is empty. Why is this not printing?
I tried threading these two click() and d() function, but nothing works
from tkinter import *
def click():
def d():
print(a.get())
w2=Tk()
a=StringVar()
E=Entry(w2,textvariable=a).pack()
b=Button(w2,text="submit",command=d).pack()
w=Tk()
b=Button(w,text="ok",command=click).pack()
mainloop()
Seems to be a problem with multiple instances of Tk(). See Why are multiple instances of Tk discouraged? Instead open the second window as Toplevel():
w2 = Toplevel(w)
I am expecting that on the click of button the label should be displayed and then the download should start. But in this below case, the frame gets stuck , say if download takes 10 min it gets stuck, and the label will be displayed only after 10.
def call():
test1()
test2()
def test1():
button.pack_forget()
label.pack()
def test2():
"script to start download which might take 10 min"
frame=Tk()
frame.pack()
button=Button(frame,text="clickme",command=call)
label=Label(frame,text="downloading...Please wait")
button.pack()
frame.mainloop()
.pack_forget() can be a bit fiddly sometimes.
Personally I prefer to pack everything into a sort of sub-master frame, which is the only direct child of the Tk() window and all contents are children of the sub-master frame.
It also seems that you're forgetting to pass the variables to call() and subsequently to test1. Due to your label and button being a local variable not global you won't be able to draw or destroy them without passing them to the routine. To do this within the restraints of the Tkinter button command system you need to use the function lambda: (Demonstrated below).
So in the case of your code, something like this:
from tkinter import *
def Call(frame, mainframe, label):
test1(frame, mainframe, label)
test2()
def test1(frame, mainframe, label)
mainframe.destroy()
mainframe = Frame(frame)
label.pack()
def test2()
print("Only here so the program can be copied straight from SO")
#Blegh, download stuff
frame = Tk()
mainframe = Frame(frame) #This is the sub-master frame
button = Button(mainframe, text="clickme", command=lambda:Call(frame, mainframe, label) #Using lambda here allows you to pass parameters to the definition within Tkinters buttons command restraints
label = Label(mainframe, text="downloading . . . Please wait")
button.pack()
frame.mainloop()
This code would function in a way where pressing the button will wipe the button from the screen and instead pack the label you wanted to pack, should you wish to keep the button for whatever reason you need only modify test1() by adding the line button.pack() and ensuring you also pass the variable as a parameter.
I'm new to Python and this is my first time using tkinter.
I'm trying to create an event where if the Enter key is pressed, my function is called passing in arguments (in this case I want to pass in my entry widget).
Here is a simplified version of my code:
def checkPassword(event):
# do stuff
from tkinter import *
import tkinter.messagebox as box
window = Tk()
window.title('Booking System')
frame = Frame(window)
Entry = Entry(frame)
Entry.bind("<KeyRelease-Return>", checkPassword)
Entry.pack()
frame.pack()
window.mainloop()
The event here is working fine, however I'm having problems when I try to pass in arguments. I've tried
def checkPassword(self, event):
# do stuff
Entry.bind("<KeyRelease-Return>", lambda event: self.checkPassword(event, Entry))
and get the error NameError: global name 'self' is not defined
And I've also tried
def checkPassword(self,event,param):
# do stuff
import functools
Entry.bind("<KeyRelease-Return>", functools.partial(checkPassword, param=Entry))
but get TypeError: checkPassword() missing 1 required positional argument: 'event'
I can't seem to fix either of these, I've looked at the solutions to similar questions on here but can't get any of them to work with my code.
Your second attempt was close, but since checkPassword isn't a class method, you shouldn't be prefixing it with self..
def checkPassword(event, some_value_you_want):
# do stuff
Entry.bind("<KeyRelease-Return>", lambda event: checkPassword(event, name_of_your_entry_widget))
Kevin's answer is correct for the general problem of including data along with the event instance, but is redundant when the extra data is the widget causing the event. Events have up to 17 attributes, including .widget, the widget that was the source of the event. (I strongly recommend the tkinter reference that includes the above link.) The following prints the contents of the entry widget when return is hit.
from tkinter import *
def checkPassword(event):
print(event.widget.get())
window = Tk()
Entry = Entry(window)
Entry.bind("<KeyRelease-Return>", checkPassword)
Entry.pack()
window.mainloop()
I need to be able to clear my tkinter window of all objects (with a function), and create the objects again with a function. However, I cannot access the objects created with my first function with the second function. I recreated my problem below.
import tkinter
window = tkinter.Tk()
def create():
test = tkinter.Button(window, text="Example", command=delete)
test.place(x=75, y=100)
def delete():
test.place_forget()
create()
window.mainloop()
This returns the error - NameError: name 'test' is not defined
Here's a quick sample of how your code might look, using an object oriented structure:
import tkinter as tk
class MyApp: # No need to inherit 'object' in Python 3
def __init__(self, root):
self.root = root
def create_button(self):
self.test_button = tk.Button(self.root,
text="Example",
command=self.delete_button)
self.test_button.place(x=75, y=100)
def delete_button(self):
self.test_button.place_forget()
def run(self):
self.create_button()
self.root.mainloop()
if __name__=='__main__':
root = tk.Tk()
app = MyApp(root)
app.run()
You create a MyApp object that 'owns' the button, and has methods that explicitly act on the things that it owns. Any method of the MyApp object has a reference to various widgets, via the self argument that automatically gets sent in.
This is a lot more code than you had before, and to be honest, for what your code does right now, it's an overkill. Malik's solution of using global is probably fine. However, if you want to add more widgets, layer them out, have them interact in more complex ways etc, then using global can introduce hard-to-find bugs, and makes it incredibly hard to wrap your head around what's going on.
Any non-trivial use of Tkinter that I have seen has used an object-oriented style similar to the above example.
As an aside, I wouldn't create the delete function - using the .config method to set the command after you create the button would be better:
def create_button(self):
self.test_button = tk.Button(self.root, text="Example")
self.test_button.config(command=self.test_button.place_forget)
self.test_button.place(x=75, y=100)
Using .config allows you to set commands that are methods of the button you just created, which you can't do when you set the command as a part of the button instantiation.
Well if you're using two different functions, you're going to need global variables:
import tkinter
window = tkinter.Tk()
test = None
def create():
global test
test = tkinter.Button(window, text="Example", command=delete)
test.place(x=75, y=100)
def delete():
global test
test.destroy() # or place_forget if you want
window.after(5000, create) # button reappears after 5 seconds
create()
window.mainloop()
Your delete function could not destroy the button as it was only defined in the create function. The workaround is to create a global variable that can be accessed by both.