python - Tkinter:实时从子进程输出更新 GUI
问题描述
我已经搜索了整个互联网来回答我的问题,但似乎没有人有相同的问题:我正在尝试从子进程输出动态更新我的 tkinter GUI,如果我在 Eclipse 中启动我的 GUI,它工作正常。但是,如果我在文件资源管理器或 Visual Studio 中运行它,则“stdout.readline”命令会等待,直到子进程完成。只有这样完整的输出才会打印到我的文本区域...我正在使用一个线程并且我尝试了两种方法:一种显示在“App.py”中,另一种是线程化“read_update”方法(并且不使用“reader_thread”和“update”方法)。
有趣的旁注:Test.py 中的 sys.argv 命令不返回我的字符串“var_test”。谁能告诉我为什么?
我的课程是:
图形用户界面.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()
应用程序.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()
测试.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()
推荐阅读
- swift - 在迁移期间移除属性
- r - 无法让 write.csv 或 write.table 在 BlueSky Statistics 的 r 编辑器中工作
- azure - VSFM 2019 - 无法读取或写入 NuGet.config
- eslint - Nuxt 应用程序中的 eslint 突然无法正常工作 - 出现错误:未找到 ESLint 配置
- google-cloud-dataproc - 从作曲家在数据处理集群上执行 bash 脚本
- pandas - 当我尝试在 python 中导入时,.csv 文件返回“unicode 错误”
- ruby-on-rails-5 - 动作电缆无法解决生产握手问题
- mysql - MySQL 从 5.7 升级到 8.0 在 Failed at step EXEC spawning mysql-systemd-start 上失败
- .net - 在 rdlc 中并排显示比较数据
- spring-boot - 使用spring security自定义授权运行一段时间后用户名和密码为空