Tkinter:实时从子进程输出更新 GUI

Tkinter: Updating GUI from subprocess output in realtime

我搜索了整个互联网来回答我的问题,但似乎没有人有相同的问题:我正在尝试从子进程输出动态更新我的 tkinter GUI,如果我开始,它工作正常我在 Eclipse 中的 GUI。但是如果我在文件资源管理器或 visual studio 中 运行 它,'stdout.readline' 命令会等待,直到子进程完成。只有这样,完整的输出才会打印到我的文本区域...我正在使用一个线程,我尝试了两种方法:一种显示在 'App.py' 中,另一种是线程化 'read_update' 方法(并且不使用 'reader_thread' 和 'update' 方法)。

有趣的旁注:Test.py 中的 sys.argv 命令不会 return 我的字符串 "var_test"。谁能告诉我为什么?

我的 类 是:

GUI.py

import Tkinter as tk

from App import App

if __name__ == '__main__':
    root = tk.Tk()

    app = App(root)

    root.protocol("WM_DELETE_WINDOW", app.quit)
    root.mainloop() 

App.py

#App.py
import Tkinter as tk
import tkFont as tkfont
import subprocess

from subprocess import Popen
from subprocess import PIPE
from itertools import islice
from threading import Thread
from ttk import Scrollbar
from Tkinter import *
from Queue import Queue, Empty

class App():
    def __init__(self, root):
        self.root = root
        self.root.title_font = tkfont.Font(family = "Helvetica", size = 18, weight = "bold", slant = "italic")

        Grid.columnconfigure(self.root, 5, weight = 1)

        button_ok = tk.Button(self.root, text = "OK", width = 10, command = lambda: self.on_okay())
        button_ok.grid(row = 7, column = 0, padx = (20,0), pady = 10, sticky = W)

        xscrollbar = Scrollbar(self.root, orient=HORIZONTAL)
        xscrollbar.grid(row=8, column=1, columnspan=4, sticky=E + W)

        yscrollbar = Scrollbar(self.root, orient=VERTICAL)
        yscrollbar.grid(row=8, column=5, sticky=N + S)

        self.textarea = Text(self.root, wrap=NONE, bd=0,
                             xscrollcommand=xscrollbar.set,
                             yscrollcommand=yscrollbar.set)
        self.textarea.grid(row=8, column=1, columnspan=4, rowspan=1,
                            padx=0, sticky=E + W + S + N)

    def on_okay(self):
        self.textarea.delete("1.0", END)

        exec_path = r"\Test.py" #insert location of Test.py

        self.process = subprocess.Popen([exec_path, 'var_test'], shell = True, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)

        self.q = Queue(maxsize = 1024)
        t = Thread(target=self.reader_thread, args=[self.q])
        t.daemon = True
        t.start()

        self.update(self.q)

    def reader_thread(self, q):
        try:
            with self.process.stdout as pipe:
                for line in iter(pipe.readline, b''):
                    q.put(line)
        finally:
            q.put(None)

    def update(self, q):
        for line in self.iter_except(q.get_nowait, Empty):
            if line is None:
                #self.quit()
                return
            else:
                self.textarea.insert(INSERT, line)
                self.textarea.yview(END)
                break
        self.root.after(40, self.update, q)

    def iter_except(self, function, exception):
        try:
            while True:
                yield function()
        except exception:
            return

    def read_update(self):
        while True:
            line = self.process.stdout.readline()
            if line == "" and self.process.poll() != None:
                break
            elif line == "":
                pass
            else:
                self.textarea.insert(INSERT, line)
                self.textarea.yview(END)
                self.textarea.update_idletasks()    

    def quit(self):
        try:
            self.process.kill()
        except AttributeError:
            pass
        finally:
            self.root.destroy()

Test.py

import sys

from time import sleep

var = sys.argv
print var

for i in range(1, 10):
    print i

print "finished printing numbers"

sleep(10)

print "finished"

感谢您的帮助!我非常绝望,因为我已经尝试解决这个问题好几个小时了...

在打印后使用 sys.stdout.flush()