简体   繁体   English

Python tkinter 维护 gui 并从 pipe 读取

[英]Python tkinter maintaining gui and reading from pipe

I am trying to achieve reading from subprocess pipe stdout and stderr and updating GUI simultaneously.我正在尝试从子进程 pipe stdout 和 stderr 读取并同时更新 GUI。 However my code is waiting all pipe reading process then updates all.但是我的代码正在等待所有 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 is a button command. run_script_from_file 是一个按钮命令。 And self.q is a Queue belongs to same class of this functions.而self.q是一个队列,属于这个函数的同一个class。

Why my text_output tk.Text field is not updating asap为什么我的 text_output tk.Text 字段没有尽快更新

Script.py:脚本.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)

Edit: I put all my code Edit: Added script.py编辑:我把我所有的代码编辑:添加了 script.py

Ok, so this is actually not too far off.好的,所以这实际上并不太远。 One common gotcha, due to buffering you have to run python in -u mode.一个常见的问题是,由于缓冲,您必须在-u模式下运行 python。 Only other thing really is to have the tkinter update loop running all the time.唯一真正的另一件事是让 tkinter 更新循环一直运行。 Try this:尝试这个:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM