Tkinter:如何使用多线程在后台保持监视功能处于活动状态
Tkinter: How use multithreading to keep a monitoring function active in the background
我正在制作一个 GUI,用于在超级计算机上可视化 SLURM 队列。我想通过 ssh(使用 paramiko)定期发送命令来持续监控队列中 运行 和待处理作业的数量,以获取队列、分析它并更新一些与 tk 标签相关的 tk 变量。
到目前为止,我一直在使用 self.after()
语法来执行此操作,并确保不要过于频繁地进行后台 SSH 调用(以免导致界面出现恼人的死机)。然而,我正在重写我的代码,我也想监控其他几个方面,但这会大大降低界面速度。
我认为这可以通过使用 threading
模块来解决,但我不确定如何正确设置它。为了这个问题,考虑以下MWE:
import tkinter as tk
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
Home(self)
class Home(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.counter = tk.IntVar()
self.counter2 = tk.IntVar()
self.grid(row=0, column=0)
tk.Label(self, text='Counter 1:').grid(row=0, column=0)
tk.Label(self, textvar=self.counter).grid(row=0, column=1)
tk.Label(self, text='Counter 2:').grid(row=1, column=0)
tk.Label(self, textvar=self.counter2).grid(row=1, column=1)
self.monitor_counter()
self.monitor_counter2()
def monitor_counter(self, end=100, delay=1000):
time.sleep(0.2)
if self.counter.get() < 0:
self.parent.destroy()
self.counter.set(end)
self.after(int(delay), lambda: self.monitor_counter(end-1))
def monitor_counter2(self, start=0, delay=1000):
time.sleep(0.2)
self.counter2.set(start)
self.after(int(delay), lambda: self.monitor_counter2(start+1))
if __name__ == '__main__':
GUI().mainloop()
它只是跟踪连接到某些标签的变化 IntVar
s,使用 sleep 语句来模拟 SSH 调用。现在的设置方式,尽管更新了计数器,但 GUI 不显示。
我如何修改上面的程序以将监视函数作为它们自己的线程生成?假设监控应该始终处于活动状态,并且用户不能在不退出程序的情况下停用它们。此外,当退出程序时调用 root.destroy()
时,当然应该终止线程。
下面是基于您使用线程的更新代码:
import tkinter as tk
import time
import threading
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
Home(self)
class Home(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.counter = tk.IntVar()
self.counter2 = tk.IntVar()
self.grid(row=0, column=0)
tk.Label(self, text='Counter 1:').grid(row=0, column=0)
tk.Label(self, textvar=self.counter).grid(row=0, column=1)
tk.Label(self, text='Counter 2:').grid(row=1, column=0)
tk.Label(self, textvar=self.counter2).grid(row=1, column=1)
# start the monitor tasks
threading.Thread(target=self.monitor_counter, daemon=True).start()
threading.Thread(target=self.monitor_counter2, daemon=True).start()
def monitor_counter(self, end=100, delay=1):
while True:
time.sleep(0.2) # simulate SSH call
if self.counter.get() < 0:
self.parent.destroy()
end -= 1
self.counter.set(end)
time.sleep(delay)
def monitor_counter2(self, start=0, delay=1):
while True:
time.sleep(0.2) # simulate SSH call
self.counter2.set(start)
start += 1
time.sleep(delay)
if __name__ == '__main__':
GUI().mainloop()
我正在制作一个 GUI,用于在超级计算机上可视化 SLURM 队列。我想通过 ssh(使用 paramiko)定期发送命令来持续监控队列中 运行 和待处理作业的数量,以获取队列、分析它并更新一些与 tk 标签相关的 tk 变量。
到目前为止,我一直在使用 self.after()
语法来执行此操作,并确保不要过于频繁地进行后台 SSH 调用(以免导致界面出现恼人的死机)。然而,我正在重写我的代码,我也想监控其他几个方面,但这会大大降低界面速度。
我认为这可以通过使用 threading
模块来解决,但我不确定如何正确设置它。为了这个问题,考虑以下MWE:
import tkinter as tk
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
Home(self)
class Home(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.counter = tk.IntVar()
self.counter2 = tk.IntVar()
self.grid(row=0, column=0)
tk.Label(self, text='Counter 1:').grid(row=0, column=0)
tk.Label(self, textvar=self.counter).grid(row=0, column=1)
tk.Label(self, text='Counter 2:').grid(row=1, column=0)
tk.Label(self, textvar=self.counter2).grid(row=1, column=1)
self.monitor_counter()
self.monitor_counter2()
def monitor_counter(self, end=100, delay=1000):
time.sleep(0.2)
if self.counter.get() < 0:
self.parent.destroy()
self.counter.set(end)
self.after(int(delay), lambda: self.monitor_counter(end-1))
def monitor_counter2(self, start=0, delay=1000):
time.sleep(0.2)
self.counter2.set(start)
self.after(int(delay), lambda: self.monitor_counter2(start+1))
if __name__ == '__main__':
GUI().mainloop()
它只是跟踪连接到某些标签的变化 IntVar
s,使用 sleep 语句来模拟 SSH 调用。现在的设置方式,尽管更新了计数器,但 GUI 不显示。
我如何修改上面的程序以将监视函数作为它们自己的线程生成?假设监控应该始终处于活动状态,并且用户不能在不退出程序的情况下停用它们。此外,当退出程序时调用 root.destroy()
时,当然应该终止线程。
下面是基于您使用线程的更新代码:
import tkinter as tk
import time
import threading
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
Home(self)
class Home(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.counter = tk.IntVar()
self.counter2 = tk.IntVar()
self.grid(row=0, column=0)
tk.Label(self, text='Counter 1:').grid(row=0, column=0)
tk.Label(self, textvar=self.counter).grid(row=0, column=1)
tk.Label(self, text='Counter 2:').grid(row=1, column=0)
tk.Label(self, textvar=self.counter2).grid(row=1, column=1)
# start the monitor tasks
threading.Thread(target=self.monitor_counter, daemon=True).start()
threading.Thread(target=self.monitor_counter2, daemon=True).start()
def monitor_counter(self, end=100, delay=1):
while True:
time.sleep(0.2) # simulate SSH call
if self.counter.get() < 0:
self.parent.destroy()
end -= 1
self.counter.set(end)
time.sleep(delay)
def monitor_counter2(self, start=0, delay=1):
while True:
time.sleep(0.2) # simulate SSH call
self.counter2.set(start)
start += 1
time.sleep(delay)
if __name__ == '__main__':
GUI().mainloop()