简体   繁体   中英

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. BUT if I'm running it in the file explorer or in visual studio, the 'stdout.readline' command waits, until the subprocess is finished. 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).

Interesting sidenote: the sys.argv command in Test.py does not return my string "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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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