简体   繁体   English

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

[英]Tkinter: Updating GUI from subprocess output in realtime

I've searched the whole internet to answer my problem, but nobody seems to have the same one: I'm trying to update my tkinter GUI dynamically from a subprocess output, which works fine, if I'm starting my GUI inside eclipse. 我已经搜索了整个互联网来回答我的问题,但是似乎没有一个人可以解决这个问题:如果要在eclipse中启动GUI,我试图从子进程输出中动态更新tkinter GUI,这很好用。 BUT if I'm running it in the file explorer or in visual studio, the 'stdout.readline' command waits, until the subprocess is finished. 但是,如果我正在文件浏览器或Visual Studio中运行它,则“ stdout.readline”命令将等待,直到子进程完成。 Only then the complete output is printed to my textarea... I am working with a thread and I've tried 2 ways: one is shown in 'App.py', the other one is threading the 'read_update' method instead (and not using 'reader_thread' and 'update' methods). 然后,才将完整的输出打印到我的textarea中。我正在使用一个线程,并且尝试了两种方法:一种在“ App.py”中显示,另一种在线程化“ read_update”方法(和不使用'reader_thread'和'update'方法)。

Interesting sidenote: the sys.argv command in Test.py does not return my string "var_test". 有趣的旁注:Test.py中的sys.argv命令不会返回我的字符串“ var_test”。 Can anyone tell me why? 谁能告诉我为什么?

My Classes are: 我的课程是:

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"

Thank you for your help! 谢谢您的帮助! I'm pretty desperate 'cause I've been trying to solve this problems for many hours now... 我非常绝望,因为我已经尝试解决这个问题很多小时了...

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM