【发布时间】:2021-09-03 14:54:12
【问题描述】:
我有一个带有文本框和运行按钮的 tkinter GUI。按下运行按钮将其变为黄色并启动打印几个数字的子程序。子例程的文本输出被重定向到 GUI 文本框。但是,在使用 pyinstaller 创建独立的可执行文件后,它不再起作用。按下运行按钮似乎不会启动子进程。它确实变成黄色,但文本框中没有出现任何文本,并且似乎启动了主程序的另一个实例 - 大约 10 秒后出现第二个 GUI,这是出现初始 GUI 所需的时间。运行按钮在初始 GUI 上保持黄色。
我在网上看到了一些关于其他人在 pyinstaller 之后没有运行子进程的问题,但大多数解决方案似乎是确保 stdout、stdin 设置为我拥有的 subprocess.PIPE,所以我有点不知所措,下一步该尝试什么。
我正在用这个创建我的独立:
pyinstaller --onefile simpleGUI.py
我的子进程文件,testsubprocess.py 是:
import time
for i in range(3):
print("%d.%d" % divmod(i, 10))
time.sleep(0.5)
我的主要 GUI 文件 simpleGUI.py 是:
import sys
import subprocess
from threading import Thread
import tkinter as tk
from queue import Queue, Empty
def iter_except(function, exception):
try:
while True:
yield function()
except exception:
return
class DisplaySubprocessOutputDemo:
def __init__(self, root):
self.root = root
width=600
height=350
xloc=0
yloc=10
self.root.geometry('%dx%d+%d+%d' % (width, height, xloc, yloc))
self.statustext = tk.Text(self.root, height=4, width=30)
self.statustext.grid(row=3, column=1)
self.startbutton = tk.Button(self.root, text = 'Start', command=self.startprocess, bg='green', activebackground = 'orange')
self.startbutton.config(height = 2, width = 15)
self.startbutton.grid(row = 5, column=0,sticky='E')
self.startbuttonpresses = 0
exitbutton = tk.Button(self.root, text = 'Exit', command=self.quit, bg='red')
exitbutton.config(height = 2, width = 15)
exitbutton.grid(row = 5, column=4, sticky='E')
def startprocess(self):
self.startbuttonpresses = self.startbuttonpresses+1
if self.startbuttonpresses == 1:
self.startbutton.configure(bg='yellow')
self.startbutton.configure(text='Stop')
self.process = subprocess.Popen([sys.executable, "-u", "testsubprocess.py"], shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
q = Queue(maxsize=1024)
t = Thread(target=self.reader_thread, args=[q])
t.daemon = True
t.start()
self.updatetext(q)
else:
self.startbuttonpresses = 0
self.process.kill()
self.startbutton.configure(bg='green')
self.startbutton.configure(text='Start')
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 updatetext(self, q):
for line in iter_except(q.get_nowait, Empty): # display all content
if line is None:
self.startbuttonpresses = 0
self.startbutton.configure(bg='green')
self.startbutton.configure(text='Start')
return
else:
self.statustext.insert(tk.END, line)
self.root.after(400, self.updatetext, q)
def quit(self):
try:
self.process.kill()
except Exception:
pass
self.root.destroy()
root = tk.Tk()
app = DisplaySubprocessOutputDemo(root)
root.protocol("WM_DELETE_WINDOW", app.quit)
root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
root.mainloop()
【问题讨论】:
-
从
Popen调试标准输出、标准错误、返回码。可能在当前工作目录中找不到testsubprocess.py -
我正在从 Anaconda 提示符运行我的可执行文件以尝试获取一些错误消息,但我什么也没得到 - 无论是在 GUI 文本框中,还是在 Anaconda 提示符窗口中。我需要做些什么来显示错误消息吗?
-
我也尝试过将 testsubprocess.py 文件显式添加到构建中:
pyinstaller --onefile --add-data "testsubprocess.py;." simpleGUI.py,但我得到了相同的结果
标签: python tkinter subprocess pyinstaller stdout