The following two methods are shown for periodic execution processing in tkinter.
--When using the threading module --When using the schedule module
For simple processing, you do not need to use the threading module or schedule module, but for heavy processing, the operation of tk itself (pressing a button / moving the screen, etc.) becomes heavy. Therefore, even if it is troublesome, it may be better to implement it by the above method.
Below is the sample code. It is a program that increases the value of "self.label" by 1. If you want to do it, you can execute it regularly in milliseconds. Since it is python, the time accuracy is not so good, but if you do not have to worry about the time accuracy so much, this is enough.
import tkinter as tk
import threading
class GUI(tk.Frame):
def __init__(self,master = None):
super().__init__(master)
self.master = master
master.geometry("300x300")
master.title("Test")
self.count = 0 #Buffer of values defined in label
self.test = tk.Frame(self.master)#It's not necessary, but I have created another frame to manage the screen.
self.test.pack()
self.label = tk.Label(self.test)
self.label.pack()
self.label["text"] = str(self.count) #Initialize label value
self.timeEvent()#Timer start
#Timer activation function
def timeEvent(self):
th = threading.Thread(target=self.update)#Thread instantiation
th.start()#Thread start
self.after(1000, self.timeEvent)#Now call the function recursively
#Thread processing entity
def update(self):
self.count += 1
print(self.count) #Debug message
self.label["text"] = str(self.count) #Update label value
if __name__ == "__main__":
gui = tk.Tk()
app = GUI(master = gui)
app.mainloop()
If you want more time accuracy, the process will be a little complicated, but you can write as follows. I think it will be twice as accurate in time, but it will be a little less readable.
import tkinter as tk
import threading
import time
class GUI(tk.Frame):
def __init__(self,master = None):
super().__init__(master)
self.master = master
master.geometry("300x300")
master.title("Test")
self.count = 0
self.test = tk.Frame(self.master)
self.test.pack()
self.label = tk.Label(self.test)
self.label.pack()
self.label["text"] = str(self.count)
self.buftime = time.time()#Timer initialization
self.timeEvent()
def timeEvent(self):
tmp = time.time()
if(tmp - self.buftime) >= 1: #When 1 sec has passed
th = threading.Thread(target=self.update)
th.start()
print(tmp - self.buftime)
self.buftime = tmp
self.after(1, self.timeEvent)
def update(self):
self.count += 1
self.label["text"] = str(self.count)
if __name__ == "__main__":
gui = tk.Tk()
app = GUI(master = gui)
app.mainloop()
You can do the same with the "schedule" module. However, this needs to be installed with pip. In addition, it seems that periodical execution in milliseconds cannot be done within the range examined.
If it is in seconds, I think that this is more readable, so it may be better to select it according to the purpose.
pip install schedule
import tkinter as tk
import schedule
class GUI(tk.Frame):
def __init__(self,master = None):
super().__init__(master)
self.master = master
master.geometry("300x300")
master.title("Test")
self.count = 0
self.test = tk.Frame(self.master)
self.test.pack()
self.label = tk.Label(self.test)
self.label.pack()
self.label["text"] = str(self.count)
schedule.every(1).seconds.do(self.update)#Add task to schedule
self.sc()
def sc(self): #Check the task status regularly with the schedule module
schedule.run_pending()
self.after(1, self.sc) #Run recursively
def update(self):
self.count += 1
print(self.count)
self.label["text"] = str(self.count)
if __name__ == "__main__":
gui = tk.Tk()
app = GUI(master = gui)
app.mainloop()
Python's "threading" module runs only once per instance declaration. This is a specification of the threading module. An example is shown below.
error.py
import threading
th = threading.Thread(target=self.update)
th.start()
th.start() #← Error here "Runtime Error": threads can only be started once」
Recommended Posts