显示一个子进程的实时输出在一个 tkinter 组件中。
显示一个子进程的实时输出在一个 tkinter 组件中。
我的问题和这个问题几乎相同:Widget to Display subprocess stdout?,但更进一步。
我有以下代码(python2.7):
def btnGoClick(p1): params = w.line.get() if len(params) == 0: return # 创建子窗口 win = tk.Toplevel() win.title('Bash') win.resizable(0, 0) # 创建一个框架以便附加滚动条 frame = ttk.Frame(win) # 文本小部件-小部件的大小定义了窗口的大小 t = tk.Text(frame, width=80, bg="black", fg="green") t.pack(side="left", fill="both") s = ttk.Scrollbar(frame) s.pack(side="right", fill="y") # 链接文本和滚动条小部件 s.config(command=t.yview) t.config(yscrollcommand=s.set) frame.pack() process = subprocess.Popen(["", params], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: out = process.stdout.readline() if out == '' and process.poll() is not None: break print out t.insert(tk.END, out)
从"长时间运行"的bash脚本中捕获的输出实时显示(出现在控制台),但Tkinter窗口只在子进程结束后才出现!
如何使窗口在子进程开始之前出现并实时更新其内容?
问题的原因是在使用tkinter构建GUI界面时,当在界面上显示一个子进程的实时输出时,使用一个无限循环来读取输出会导致界面被阻塞,无法进行其他操作。这是因为循环的执行会一直占用主线程,导致用户无法进行其他操作。
解决方法是将读取子进程输出的部分放在一个单独的线程或进程中执行。可以使用Python的多线程或多进程模块来实现。另外,如果使用pygtk库,可以使用gobject.io_add_watch()函数来实现这个功能。
下面是两个示例代码的链接,一个使用了gobject.io_add_watch()函数,另一个使用了多线程来实现实时输出显示:
- [使用io_add_watch()函数的示例](https://gist.github.com/zed/8a255e81eb87431c0e63)
- [使用多线程的示例](https://gist.github.com/zed/8a255e81eb87431c0e63)
问题的原因是希望将subprocess的实时输出显示在一个tkinter的Text小部件中。解决方法是使用subprocess.Popen来执行命令,并通过stdout参数将输出重定向到一个变量中,然后将该变量的内容逐行插入到Text小部件中。
具体的解决方法如下:
1. 首先,在tkinter中创建一个Text小部件,用于显示实时输出的日志。
log_box_1 = tk.Text(root, borderwidth=3, relief="sunken")
2. 使用subprocess.Popen来执行命令,并将stdout参数设置为subprocess.PIPE,以便将输出重定向到一个变量中。
with subprocess.Popen("ls -la", shell=True, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True) as p:
3. 使用循环遍历subprocess的stdout输出,并将每行内容逐行插入到Text小部件中。
for line in p.stdout: log_box_1.insert(tk.END, line)
这样,通过以上步骤,就可以实现将subprocess的实时输出显示在tkinter的Text小部件中。
以上解决方法的来源是来自这里的一个来源。