[英]Python tkinter maintaining gui and reading from pipe
我正在尝试从子进程 pipe stdout 和 stderr 读取并同时更新 GUI。 但是我的代码正在等待所有 pipe 读取过程,然后全部更新。
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
import subprocess
import threading
import time
from queue import *
class Application:
# load main window of application
def __init__(self, master):
self.current_script_file_name = None
self.q = Queue()
self.window = master
self.window.title("TK")
self.window.rowconfigure(1, minsize = 600, weight = 2)
self.window.columnconfigure(1, minsize = 600, weight= 2)
# create frame for buttons and create buttons
self.frame_buttons = tk.Frame(master = self.window, relief = tk.RAISED, bd = 2)
self.button_save = tk.Button(master = self.frame_buttons, text = "Save", command = self.save_script_to_file)
self.button_run = tk.Button(master = self.frame_buttons, text = "Run", command = self.run_script_from_file)
# create frame for tk.Text editor and output
self.frame_text = tk.Frame(master = self.window, relief = tk.RAISED, bd = 2)
self.text_editor = tk.Text(self.frame_text)
self.text_output = tk.Text(self.frame_text, background = "Black", foreground = "White")
#adjust buttons
self.button_save.grid(row = 0, column = 0, sticky = "ew", padx = 5, pady = 5)
self.button_run.grid(row = 1, column = 0, sticky = "ew", padx = 5)
self.frame_buttons.grid(row = 0, column = 0, sticky = "ns")
#adjust text editor and text output
self.text_editor.grid(row = 0, column = 0, sticky = "ew", padx = 10, pady = 10)
self.text_output.grid(row = 1, column = 0, sticky = "ew", padx = 5, pady = 5)
self.frame_text.grid(row = 0, column = 1, sticky = "ns")
self.text_output.insert(tk.END, 'Script Result:\n')
def run(self):
self.window.mainloop()
def save_script_to_file(self):
file_path = asksaveasfilename(
filetypes=[("Python Scripts", "*.py"), ("Kotlin Scripts", "*.kts*")]
)
if not file_path:
return
with open(file_path, "w") as output_file:
text = self.text_editor.get(1.0, tk.END)
output_file.write("#!/usr/bin/env python3\n")
output_file.write(text)
self.window.title(f"Text Editor Application - {file_path}")
def run_script_from_file(self):
# start thread so main window not going to freeze
threading.Thread(target=self.run_script).start()
self.update()
def run_script(self):
sub_proc = subprocess.Popen(['python','script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
threading.Thread(target=self.pipe_reader, args=[sub_proc.stdout]).start()
threading.Thread(target=self.pipe_reader, args=[sub_proc.stderr]).start()
def update(self):
while not self.q.empty():
for source, line in iter(self.q.get, None):
self.text_output.insert(tk.END,line)
self.window.after(1000,self.update)
def pipe_reader(self, pipe):
try:
with pipe:
for line in iter(pipe.readline, b''):
self.q.put((pipe, line))
finally:
self.q.put(None)
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
app.run()
run_script_from_file 是一个按钮命令。 而self.q是一个队列,属于这个函数的同一个class。
为什么我的 text_output tk.Text 字段没有尽快更新
脚本.py:
#!/usr/bin/env python3
import time
counter = 1
while counter < 6:
print ("The current counter value: %d" % counter)
counter = counter + 1
time.sleep(1)
print(asd)
编辑:我把我所有的代码编辑:添加了 script.py
好的,所以这实际上并不太远。 一个常见的问题是,由于缓冲,您必须在-u
模式下运行 python。 唯一真正的另一件事是让 tkinter 更新循环一直运行。 尝试这个:
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
import subprocess
import threading
import time
from queue import *
class Application:
# load main window of application
def __init__(self, master):
self.current_script_file_name = None
self.q = Queue()
self.window = master
self.window.title("TK")
self.window.rowconfigure(1, minsize = 600, weight = 2)
self.window.columnconfigure(1, minsize = 600, weight= 2)
# create frame for buttons and create buttons
self.frame_buttons = tk.Frame(master = self.window, relief = tk.RAISED, bd = 2)
self.button_save = tk.Button(master = self.frame_buttons, text = "Save", command = self.save_script_to_file)
self.button_run = tk.Button(master = self.frame_buttons, text = "Run", command = self.run_script_from_file)
# create frame for tk.Text editor and output
self.frame_text = tk.Frame(master = self.window, relief = tk.RAISED, bd = 2)
self.text_editor = tk.Text(self.frame_text)
self.text_output = tk.Text(self.frame_text, background = "Black", foreground = "White")
#adjust buttons
self.button_save.grid(row = 0, column = 0, sticky = "ew", padx = 5, pady = 5)
self.button_run.grid(row = 1, column = 0, sticky = "ew", padx = 5)
self.frame_buttons.grid(row = 0, column = 0, sticky = "ns")
#adjust text editor and text output
self.text_editor.grid(row = 0, column = 0, sticky = "ew", padx = 10, pady = 10)
self.text_output.grid(row = 1, column = 0, sticky = "ew", padx = 5, pady = 5)
self.frame_text.grid(row = 0, column = 1, sticky = "ns")
self.text_output.insert(tk.END, 'Script Result:\n')
self.update()
def save_script_to_file(self):
file_path = asksaveasfilename(
filetypes=[("Python Scripts", "*.py"), ("Kotlin Scripts", "*.kts*")]
)
if not file_path:
return
with open(file_path, "w") as output_file:
text = self.text_editor.get(1.0, tk.END)
output_file.write("#!/usr/bin/env python3\n")
output_file.write(text)
self.window.title(f"Text Editor Application - {file_path}")
def run_script_from_file(self):
sub_proc = subprocess.Popen(['python3', '-u','script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
threading.Thread(target=self.pipe_reader, args=[sub_proc.stdout]).start()
threading.Thread(target=self.pipe_reader, args=[sub_proc.stderr]).start()
def update(self):
while not self.q.empty():
source, line = self.q.get()
if line is None:
line = "DONE"
self.text_output.insert(tk.END,line)
self.window.after(100, self.update)
def pipe_reader(self, pipe):
for line in iter(pipe.readline, b''):
self.q.put((pipe, line))
self.q.put((pipe, None))
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
root.mainloop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.