我试图在我的 tkinter GUI 主任务中显示来自后台任务的计数变量。为什么?我想显示正在执行耗时较长的后台任务,然后使用此计数变量通过进度条将其可视化。
我的问题是,即使使用 Queue
,我也无法显示计数变量。也许我在理解 python 及其对对象和/或线程的行为时遇到了问题。
import threading
import time
import Queue
import Tkinter as Tk
import Tkconstants as TkConst
from ScrolledText import ScrolledText
from tkFont import Font
import loop_simulation as loop
def on_after_elapsed():
while True:
try:
v = dataQ.get(timeout=0.1)
except:
break
scrText.insert(TkConst.END, str(v)) # "value=%d\n" % v
scrText.see(TkConst.END)
scrText.update()
top.after(100, on_after_elapsed)
def thread_proc1():
x = -1
dataQ.put(x)
x = loop.loop_simulation().start_counting()
# th_proc = threading.Thread(target=x.start_counting())
# th_proc.start()
for i in range(5):
for j in range(20):
dataQ.put(x.get_i())
time.sleep(0.1)
# x += 1
time.sleep(0.5)
dataQ.put(x.get_i())
top = Tk.Tk()
dataQ = Queue.Queue(maxsize=0)
f = Font(family='Courier New', size=12)
scrText = ScrolledText(master=top, height=20, width=120, font=f)
scrText.pack(fill=TkConst.BOTH, side=TkConst.LEFT, padx=15, pady=15, expand=True)
th = threading.Thread(target=thread_proc1)
th.start()
top.after(100, on_after_elapsed)
top.mainloop()
th.join()
在thread_proc1()
中我想得到后台任务计数器的值。这是后台任务:
import time
class loop_simulation:
def __init__(self):
self.j = 0
# self.start_counting()
def start_counting(self):
for i in range(0, 1000000):
self.j = i
time.sleep(0.5)
def get_i(self):
return str(self.j)
最佳答案
计数变量没有显示的原因是
x = loop.loop_simulation().start_counting()
thread_proc1()
中的语句。这将创建一个 loop_simulation
实例并调用其 start_counting()
方法。但是,除了已经将 -1
插入到 dataQ
之外,thread_proc1()
在 start_counting() 之前不会执行任何其他操作
返回,不会持续很长时间(500K 秒)。
与此同时,脚本的其余部分正在运行并仅显示放入的初始 -1
。
另请注意,如果 start_counting()
曾经返回,则其 None
的值将被分配给 x
,稍后代码将尝试配合使用:x.get_i()
。
下面是修复这些问题并遵循 PEP 8 - Style Guide for Python Code 的代码返工更紧密。为了避免调用 start_counting()
的主要问题,我将您的 loop_simulation
类更改为 threading.Thread
的子类并将其重命名为 LoopSimulation
,并在 thread_proc1
中创建它的一个实例,因此除了处理基于 tkinter 的 GUI 的主线程之外,现在还有两个后台线程。
import loop_simulation as loop
from ScrolledText import ScrolledText
import threading
import Tkinter as Tk
import Tkconstants as TkConst
from tkFont import Font
import time
import Queue
def on_after_elapsed():
# removes all data currently in the queue and displays it in the text box
while True:
try:
v = dataQ.get_nowait()
scrText.insert(TkConst.END, str(v)+'\n')
scrText.see(TkConst.END)
except Queue.Empty:
top.after(100, on_after_elapsed)
break
def thread_proc1():
dataQ.put(-1)
ls = loop.LoopSimulation() # slow background task Thread
ls.start_counting()
while ls.is_alive(): # background task still running?
for i in range(5):
for j in range(20):
dataQ.put(ls.get_i())
time.sleep(0.1)
time.sleep(0.5)
dataQ.put('background task finished')
top = Tk.Tk()
dataQ = Queue.Queue(maxsize=0)
font = Font(family='Courier New', size=12)
scrText = ScrolledText(top, height=20, width=120, font=font)
scrText.pack(fill=TkConst.BOTH, side=TkConst.LEFT, padx=15, pady=15,
expand=TkConst.YES)
th = threading.Thread(target=thread_proc1)
th.daemon = True # OK for main to exit even if thread is still running
th.start()
top.after(100, on_after_elapsed)
top.mainloop()
loop_simulation.py
模块:
import threading
import time
class LoopSimulation(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True # OK for main to exit even if instance still running
self.lock = threading.Lock()
self.j = 0
start_counting = threading.Thread.start # an alias for starting thread
def run(self):
for i in range(1000000):
with self.lock:
self.j = i
time.sleep(0.5)
def get_i(self):
with self.lock:
return self.j
关于python - 在主任务中显示来自后台任务的计数变量(Tkinter GUI),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38895552/