How to send subprocess text output to a Tkinter text widget? How to send subprocess text output to a Tkinter text widget? tkinter tkinter

How to send subprocess text output to a Tkinter text widget?


Here's something that uses multithreading that seems to do what you want. The main program is split into a portion that handles the QUI and a separate workerthread that manages the ping subprocess, collecting the results from it and putting them in a Queue whose contents periodically get transferred to the GUI.

It uses time.sleep() because it's done in a separate thread that's not using tkinter so it's OK.

Note, seems likely you'll might want to add a vertical scrollbar to the GUI.

import subprocessimport queueimport threadingimport timeimport tkinter as tkclass GuiPart:    def __init__(self, master, queue, end_command):        self.queue = queue        self.master = master        self.textbox = tk.Text(root)        self.textbox.pack()        btn = tk.Button(master, text='Quit', command=end_command)        btn.pack(expand=True)    def process_incoming(self):        """ Handle all messages currently in the queue. """        while self.queue.qsize():            try:                info = self.queue.get_nowait()                self.textbox.insert(tk.INSERT, info)            except queue.Empty:  # Shouldn't happen.                passclass ThreadedClient:    """ Launch the main part of the GUI and the worker thread.        periodic_call() and end_application() could reside in the GUI part, but        putting them here keeps all the thread controls in a single place.    """    def __init__(self, master):        self.master = master        self.queue = queue.Queue()        # Set up the GUI part.        self.gui = GuiPart(master, self.queue, self.end_application)        # Set up the background processing thread.        self.running = True        self.thread = threading.Thread(target=self.workerthread)        self.thread.start()        # Start periodic checking of the queue.        self.periodic_call(200)    def periodic_call(self, delay):        """ Every delay ms process everything new in the queue. """        self.gui.process_incoming()        if not self.running:            sys.exit(1)        self.master.after(delay, self.periodic_call, delay)    # Runs in separate thread - NO tkinter calls allowed.    def workerthread(self):        while self.running:            with open('servers.txt', 'r') as file:                for ip in file:                    rc = subprocess.Popen(["ping", "-c", "7", "-n", "-W", "2", ip]).wait()                    if rc:                        self.queue.put('ip address {} is inactive\n'.format(ip))                    time.sleep(1)    def end_application(self):        self.running = False  # Stop queue checking.        self.master.quit()if __name__ == '__main__':    root = tk.Tk()    root.title('Pinger')    client = ThreadedClient(root)    root.mainloop()  # Display application window and start tkinter event loop.