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.