Reputation: 7303
I am making a tkinter code that uses button widget but when I press the button, it stays pushed until the function which is executed on button press is not completed. I want the button to be released immediately and execute the function. Here is a code that shows a good example of the happening:
from tkinter import *
import time
root = Tk()
root.geometry('100x100+100+100') # size/position of root
def callback(): # this function will run on button press
print('Firing in 3')
time.sleep(3) # wait for 3 seconds
def main(): #function 'main'
b = Button(root, text="ᖴIᖇE", width=10,height=2, command=callback)# setting the button
b["background"] = 'red' #button color will be red
b["activebackground"] = 'yellow' #button color will be yellow for the time when the button will not be released
b.place(x=25,y=25) #placing the button
main() # using function 'main'
mainloop()
Upvotes: 0
Views: 4794
Reputation: 494
You can use threading
inside the function you're being blocked while pressed. This is my edit on yours:
from tkinter import *
import time
import threading
root = Tk()
root.geometry('100x100+100+100') # size/position of root
def callback(): # this function will run on button press
def callback2():
print('Firing in 3')
time.sleep(3) # wait for 3 seconds
threading.Thread(target=callback2).start()
def realcallback():
print('Firing now')
def main(): # function 'main'
b = Button(
root,
text="Fire",
width=10,
height=2,
command=callback
) # setting the button
b["background"] = 'red' # button color will be red
# button color will be yellow for the time when the button will not be released
b["activebackground"] = 'yellow'
b.place(x=25, y=25) # placing the button
main() # using function 'main'
mainloop()
Upvotes: 1
Reputation: 110146
GUI programs are typically driven in a single thread, which is controlled by the "main loop" of the graphic toolkit in use. That is: a program usually set up the application, and pass the control to the toolkit, which runs a tight loop that answers all users (and network, file, etc...) events, and the only user code ever to run again are the callbacks coded during the setup phase.
At the same time, when your code is running in during a callback, it holds controls - which means the toolkit won't be able to answer to any events while your function does not return.
What has to be done is to write code that cooperates with the GUI toolkit - that is, create events that generate further callbacks, if you need things spaced in time. In the case of tkinter, this is achieved with the method .after
of a widget: after that many milliseconds, the callable passed will be run. time.sleep
, on the other hand, stops the single thread there, and the event loop does not run.
In your example, you can simply write:
from tkinter import *
import time
root = Tk()
root.geometry('100x100+100+100') # size/position of root
def callback(): # this function will run on button press
print('Firing in 3')
root.after(3000, realcallback)
def realcallback():
print('Firing now!')
def main(): #function 'main'
b = Button(root, text="ᖴIᖇE", width=10,height=2, command=callback)# setting the button
b["background"] = 'red' #button color will be red
b["activebackground"] = 'yellow' #button color will be yellow for the time when the button will not be released
b.place(x=25,y=25) #placing the button
main() # using function 'main'
mainloop()
Upvotes: 3
Reputation: 1
I would like to add:
from tkinter import *
import time
root = Tk()
root.geometry('100x100+100+100') # size/position of root
def callback(): # this function will run on button press
root.update() #<- this works for me..
print('Firing in 3')
root.after(3000, realcallback)
def realcallback():
print('Firing now!')
def main(): #function 'main'
b = Button(root, text="ᖴIᖇE", width=10,height=2, command=callback)# setting the button
b["background"] = 'red' #button color will be red
b["activebackground"] = 'yellow' #button color will be yellow for the time when the button will not be released
b.place(x=25,y=25) #placing the button
main() # using function 'main'
mainloop()
Upvotes: 0