Python TKinter GUI冻结,直到子流程结束并实时输出到文本小部件
我正在尝试向我不久前创建的GUI添加一些功能,特别是我需要的功能是一个文本小部件,我发送的终端命令显示它们的输出。 重定向器类目前看起来如下所示:Python TKinter GUI冻结,直到子流程结束并实时输出到文本小部件,python,user-interface,tkinter,subprocess,python-multiprocessing,Python,User Interface,Tkinter,Subprocess,Python Multiprocessing,我正在尝试向我不久前创建的GUI添加一些功能,特别是我需要的功能是一个文本小部件,我发送的终端命令显示它们的输出。 重定向器类目前看起来如下所示: class StdRed(object): def __init__(self, textwid): self.text_space = textwid def write(self, text): self.text_space.config(state=NORMAL) self.t
class StdRed(object):
def __init__(self, textwid):
self.text_space = textwid
def write(self, text):
self.text_space.config(state=NORMAL)
self.text_space.insert(END,text)
self.text_space.see(END)
self.text_space.update_idletasks()
self.text_space.config(state=DISABLED)
def flush(self):
pass
事实上,它是有效的。我将os.system(…)命令替换为打开终端命令
a=subprocess.Popen(命令,stdout=PIPE,stderr=stdout,shell=True)
我通读stdout:b=a.stdout.read()
,没有任何问题(不幸的是,我需要shell=True,否则我需要调用的一些程序会失败得很惨)。
之后,我尝试在tkinter文本小部件上获得实时输出,因此我更改了b-->
但是,似乎只有在被调用的进程结束时才显示输出,例如,一个简单的C软件
对于(int i=0;i这里的解决方案是使用线程,否则脚本将等待作业完成,以使GUI再次响应。使用线程,您的程序将同时运行作业和GUI,代码示例:
import threading
def function():
pass
t = threading.Thread(target=function)
t.daemon = True # close pipe if GUI process exits
t.start()
我使用了这个std重定向器:
class StdRedirector():
"""Class that redirects the stdout and stderr to the GUI console"""
def __init__(self, text_widget):
self.text_space = text_widget
def write(self, string):
"""Updates the console widget with the stdout and stderr output"""
self.text_space.config(state=NORMAL)
self.text_space.insert("end", string)
self.text_space.see("end")
self.text_space.config(state=DISABLED)
我尝试使用@Pau B建议的线程(最终切换到多处理),我确实解决了GUI卡住的问题
为了(int i=0;i也许这可以帮助其他人,我解决了用endl替换'\n'的问题。while循环中的cout似乎是缓冲的,stdout flush只在一段时间后调用,而endl函数在每个周期后调用。我很久以前在python中搜索了如何使用线程,但是如果我没记错,您无法确定一个线程,不是吗?出于这个原因,我在GUI中使用了多处理(我也尝试在进程中打开一个子进程,但结果很差)线程在函数完成时终止。上周我不得不在Tkinter GUI中实现这样一个控制台,线程工作得很好!我会试试看,你有没有关于实时问题的线索?实时问题是因为我告诉过你,python将忙于处理进程,只有当它完成后才会继续使用tkinter主循环。对于std重定向,我使用了这个类(编辑了我的答案)。不幸的是,即使这样,程序也不能正常工作。如果你想检查,我用一个示例程序编辑了我的问题。你介意发布完整的答案吗?我不知道endl是什么
#include <iostream>
using namespace std;
int main()
{
int i = 0;
while(1)
{
cout << i << '\n';
i++;
int a = 0;
while(a < 10E6)
{
a++;
}
}
}
import threading
def function():
pass
t = threading.Thread(target=function)
t.daemon = True # close pipe if GUI process exits
t.start()
class StdRedirector():
"""Class that redirects the stdout and stderr to the GUI console"""
def __init__(self, text_widget):
self.text_space = text_widget
def write(self, string):
"""Updates the console widget with the stdout and stderr output"""
self.text_space.config(state=NORMAL)
self.text_space.insert("end", string)
self.text_space.see("end")
self.text_space.config(state=DISABLED)
class StdRed(object):
def __init__(self, textwid):
self.text_space = textwid
def write(self, text):
self.text_space.config(state=NORMAL)
self.text_space.insert(END,text)
self.text_space.see(END)
self.text_space.update_idletasks()
self.text_space.config(state=DISABLED)
def termexe(execute):
a = Popen(execute, shell=True, stdout=PIPE, stderr=STDOUT)
while True:
line = a.stdout.readline().rstrip()
if not line:
break
else:
queue.put(line)
queue.put('')
def labterm():
global th
if queue.empty():
if th != None:
if th.is_alive():
root.after(0,labterm)
else:
pass
else:
pass
else:
q = queue.get()
print q
root.after(1,labterm)
def comter(event=None):
global enter
global th
if th != None:
if not th.is_alive():
th = Process(target=termexe, args=(enter.get(),))
th.start()
else:
pass
else:
th = Process(target=termexe, args=(enter.get(),))
th.start()
enter.set('')
labterm()