Good morning,
What I am aiming for:
- I want to create a button that when clicked triggers a call back function (even if that function is still running).
Module:
- I am using tkinter
Problem:
- When I trigger the button, the function runs, but then I cannot push the button again before the function has finished its run. I want to be able to push the button while the function is still running and have the function stop and run again from start.
My attempts:
- I tried both a procedural and a OOP approach: both present the same problem
My attempt n1: Procedural approach
import time
import tkinter as tk # Import tkinter
from tkinter import ttk # Import ttk
def func():
for i in range (100):
print(i)
time.sleep(5)
win = tk.Tk() # Create instance of the Tk class
aButton = ttk.Button(win, text="Click Me!", command=func)
aButton.grid(column=0, row=0) # Adding a Button
win.mainloop() # Start GUI
My attempt n2: OOP approach
import time
import tkinter as tk # Import tkinter
from tkinter import ttk # Import ttk
class OOP():
def func(self):
for i in range (100):
print(i)
time.sleep(5)
def __init__(self):
win = tk.Tk() # Create instance of the Tk class
aButton = ttk.Button(win, text="Click Me!", command=self.func)
aButton.grid(column=0, row=0) # Adding a Button
win.mainloop() # Start GUI
oop = OOP()
Thanks
CodePudding user response:
In tkinter, as with most GUI frameworks, there is a for
loop running somewhere that constantly checks for user input. You are hijacking that loop to do your func
processing. Tkinter can not check for user input, nor e.g. change the appearance of the button icon, because there is only one thread and you are using it.
What you will want to do is fire up a thread or process to do the work. There are lots of libraries to do parallel processing in elaborate ways if you have lots of background tasks but this will do for a single function (see also this answer).
import time
import tkinter as tk # Import tkinter
from tkinter import ttk # Import ttk
import threading
def button():
thread = threading.Thread(target=func, args=args)
thread.start()
def func():
for i in range (100):
print(i)
time.sleep(5)
win = tk.Tk() # Create instance of the Tk class
aButton = ttk.Button(win, text="Click Me!", command=button)
aButton.grid(column=0, row=0) # Adding a Button
win.mainloop() # Start GUI
If the process is long running, you might need to find a way to clean up the threads when they're done.