python - 在主任务中显示来自后台任务的计数变量(Tkinter GUI)

标签 python multithreading python-2.7 user-interface tkinter

我试图在我的 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/

相关文章:

python - 根据数字从列表中获取数据

python - 无法将 pip 从 1.5.4 升级到最新版本

python - 将类装饰器传播到继承的类

c++ - Qt 信号参数线程安全

multithreading - 消息如何在多个 WndProcs 之间序列化?

wpf - 无法在多线程中操作ObservableCollection

python-2.7 - Python & Ubuntu 14.04\ 删除手动安装的python版本

python - 在 Python 中混淆字符串

python - Unicode编码错误: 'decimal' codec can't encode character u'\x00' in position 8: invalid decimal Unicode string

numpy - 使用 NumPy 读取大格式文本文件