Trying this again...I have a Python programmed GUI in which the pressed Button retains a depressed look after the event handler exits. The event handler made use of a messagebox. Normally, this does not happen. Here is an example that recreates the problem:
import tkinter as tk
from tkinter import messagebox
# post a message
def post_message(event):
messagebox.showinfo("Sample Messgebox", "close this and look at button")
root = tk.Tk()
b = tk.Button(root, text="Press Me")
b.bind("<Button-1>", func=post_message)
b.pack()
root.mainloop()
When you use the blind with the event Button-1, you aren't using the main event of the button. You can active the main event of the button with the argument command.
import tkinter as tk
from tkinter import messagebox
def post_message():
messagebox.showinfo("Sample Messgebox", "close this and look at button")
root = tk.Tk()
b = tk.Button(root, text="Press Me", command=post_message)
b.pack()
root.mainloop()
While I'm not sure why your code isn't working properly, since I'm fairly new to Py, I managed to rewrite it to work with minimal changes.
Solution 1
import tkinter as tk
from tkinter import messagebox
# post a message
def post_message():
messagebox.showinfo("Sample Messgebox", "close this and look at button")
root = tk.Tk()
b = tk.Button(root, text="Press Me", command=post_message)
b.pack()
root.mainloop()
What I changed:
no more bind() as this caused problem, instead the function is called by adding command= option while declaring Button object,
also notice that command option doesn't provide function called with event parameter, so this had to be removed or else errors would occur.
Another workaround, this time it works with bind() just fine!
Solution 2
import tkinter as tk
from tkinter import messagebox
# post a message
def post_message(event):
root.after(0, lambda: messagebox.showinfo\
("Sample Messgebox", "close this and look at button"))
root = tk.Tk()
b = tk.Button(root, text="Press Me")
b.bind("<Button-1>", post_message)
b.pack()
root.mainloop()
I used master.after(time_in_ms, callback_func) to tell the program that it should run a given func after the given time, here 0ms so ASAP.
Why is that lambda inside after? Lambda is a dynamic, not-named function. After takes a reference to the function you want called, so you can't directly give it parameters.
To do so, like in this example, set up a lambda that will be refrenced.
When it finally gets called, that lambda func will then call the actual function you wanted to call giving it the parameters it needs.
If you don't know yet how lambdas work, I know you're confused right now, so read more on them here, they're super-useful: Lambdas explained
For great source of info on tkinter, please visit effbot.org Events and Bindings
Related
import tkinter
win=tkinter.Tk()
win.configure(background='grey')
k=False
def g():
k=True
v=tkinter.Button(win, text='click', command=g)
v.pack()
while k==True:
win.configure(background='black')
win.mainloop()
There's no reason why that while loop would run after the button is clicked, since (as you know) your program is run "from top to bottom", and control remains in win.mainloop() until the window is closed. (You can find that out by adding print("bye!") after that call.)
You might want to just directly call .configure(). (I gave the button some padding here so you can see the background change; otherwise the button may take up the entirety of the window and you won't see a change.)
import tkinter
win = tkinter.Tk()
def change_color():
win.configure(background='black')
button = tkinter.Button(win, text='click', command=change_color)
button.pack(padx=10, pady=10)
win.mainloop()
Let's say if we write something like this:
import threading
Button(root, command=threading.Thread(target=func1).start)
Now if we click the button once then it will be fine but we try to click the button again then a error comes "Thread can only be executed once".
So, how to avoid this
Edited Answer::
As you clarified it in comments, you can redefine the Button every time it is clicked allowing it to accept multiple clicks and thus creating multiple threads as required.
You could do that inside the target func1() or callback function for threading.Thread object.
A working example example would be like this:
import tkinter as tk
import threading
def func1():
theButton.configure(command=threading.Thread(target=func1).start)
print('Do everything else here')
root = tk.Tk()
theButton = tk.Button(root, text='Start', command=threading.Thread(target=func1).start)
theButton.pack()
root.mainloop()
Edit: Thanks to CoolCloud for suggesting a better way to configure the Button inside callback func1().
It is because you create one instance of threading.Thread() and pass its start method to command option of the button. You should create new instance whenever the button is clicked by using lambda:
import tkinter as tk
import threading
root = tk.Tk()
def func1():
print('Hello')
tk.Button(root, text='Go', command=lambda: threading.Thread(target=func1).start()).pack()
root.mainloop()
I did some research in Tkinter and found the root.bind('<Control-Key-whatever key', function).
I wanted to add this to an application I was making.
I made a button and I want it to perform a function when I click a certain key combination.
Here is my code:
from tkinter import *
root = Tk()
root.geometry("600x600")
def printFunction():
print("Hello World")
root.bind('<Control-Key-v>', printFunction)
button = Button(root, text="click here", command=printFunction)
button.pack()
root.mainloop()
So when I click the button the function should perform, and when I click Ctrl+v the function should perform. The button works fine, but the key combination does not work. How do I fix this?
It should be something like
root.bind('<Control-v>', printFunction)
But keep in mind, this will again throw another error, because you have to pass event as a parameter to the function.
def printFunction(event=None):
print("Hello World")
Why event=None? This is because your button is also using the same function as a command but without any arguments passed to it on declaration. So to nullify it, this is a workaround.
Alternatively, your could also pass something like *args instead of event:
def printFunction(*args):
print("Hello World")
Hope you understood better.
Cheers
You can use
from tkinter import *
root = Tk()
root.geometry("600x600")
def printFunction(event):
print("Hello World")
button = Button(root, text="click here", command=lambda:printFunction(None))
root.bind('<Control-v>', printFunction)
button.pack()
root.mainloop()
Argument event is needed for the concerned function
Event name should be converted to <Control-v>
Don't forget to add lambda just before the function name call from
the button in order to call without issue by any means.
Friends, I'm trying to make hover effect in python(3.5.2) on a button, I use the below code.
from tkinter import *
root = Tk()
root.geometry("200x200+400+400")
myBtn = Button(root, text="TEST")
myBtn.pack(padx=10, pady=10)
myBtn.bind("<Enter>", lambda event, h=myBtn: h.configure(bg="red"))
myBtn.bind("<Leave>", lambda event, h=myBtn: h.configure(bg="yellow"))
root.mainloop()
It works strange.
when I hover mouse over the button, first time nothing happens
and when I leave, it gives yellow (satisfying the second event binded).
I couldn't find where I made mistake. could some one point me out
In your <Enter> binding you just need to set activebackground instead of the plain background (bg is a synonym of background).
import tkinter as tk
root = tk.Tk()
root.geometry("200x200+400+400")
myBtn = tk.Button(root, text="TEST")
myBtn.pack(padx=10, pady=10)
myBtn.bind("<Enter>", lambda event, h=myBtn: h.configure(activebackground="red"))
myBtn.bind("<Leave>", lambda event, h=myBtn: h.configure(bg="yellow"))
root.mainloop()
I changed the import statement from the messy "star" import, which imports 135 Tkinter names into your namespace. This requires a little more typing, but it makes the code easier to read & maintain because it makes it obvious which names come from Tkinter.
I've been working on a simple program that make a button output something. But when i run it,
this
(I got this from the internet btw) does not show up. Is somethoing wrong with the code or something?
Please help me so the window above can appear :)
Code:
from Tkinter import *
def asdf():
print('test')
tk = Tk()
b = Button(tk, text="test", command=asdf)
b.pack()
You forgot to call the Tk.mainloop method at the end of your program:
from Tkinter import *
def asdf():
print('test')
tk = Tk()
b = Button(tk, text="test", command=asdf)
b.pack()
##############
tk.mainloop()
##############
Doing so starts Tkinter's main event loop and creates the window.
It seems you are using Python3, as there are parentheses after print, so from Tkinter import * should be from tkinter import *. Python is case-sensitive. You also forgot to call root.mainloop() at the end of your code as #user2555451 mentioned, although a window should appear all the same, but stop responding when any event occurs (e.g., clicks, key presses, focus changes).