Tkinter: обновление графического интерфейса из вывода подпроцесса в реальном времени - PullRequest
0 голосов
/ 21 мая 2018

Я искал весь интернет, чтобы ответить на мою проблему, но, похоже, ни у кого не было той же самой: я пытаюсь динамически обновлять свой графический интерфейс tkinter из вывода подпроцесса, который работает нормально, если я запускаю свой графический интерфейсвнутри затмения.НО, если я запускаю его в проводнике или в Visual Studio, команда «stdout.readline» ждет, пока подпроцесс не будет завершен.Только после этого весь вывод выводится в мою текстовую область ... Я работаю с потоком, и я попробовал 2 способа: один показан в «App.py», другой вместо этого использует метод read_update (ине использует методы 'reader_thread' и 'update').

Интересный sidenote: команда sys.argv в Test.py не возвращает мою строку "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"

Спасибо за помощь!Я в отчаянии, потому что я пытаюсь решить эту проблему уже много часов ...

1 Ответ

0 голосов
/ 21 мая 2018

используйте sys.stdout.flush () после печати

...