Nouman
Nouman

Reputation: 7303

Tkinter button stays pressed

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

Answers (3)

Mahmudur Rahman Shovon
Mahmudur Rahman Shovon

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

jsbueno
jsbueno

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

Luis Noe Raygoza C.
Luis Noe Raygoza C.

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

Related Questions