Using tkinter and python to continuously display the output from a system command

I put an answer to a stackoverflow question. The poster wanted to display the output from a ‘netstat’ command every second. I suggested using a tkinter screen. To run the nestat command every second, the command line entry would be ‘netstat 1’. This is fed to a subprocess. This subprocess is wrapped in a thread to avoid blocking the main thread. The main thread needs to be left to deal with the tkinter display. GUIs like to hog the main thread. Don’t forget to use the ‘undo=False’ option with tk.screen. Otherwise all of the display is continuously saved to a buffer. This results in the python process gobbling up memory continuously as the output from netstat is added to it each second.

import threading
from subprocess import Popen, PIPE
from time import sleep
import tkinter as tk
from tkinter import *

 

PROCESS = ['netstat','1']
class Console(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.text = tk.Text(self, undo=False)
        self.text.pack(expand=True, fill="both")
        # run process in a thread to avoid blocking gui
        t = threading.Thread(target=self.execute)
        t.start()
 
 
    def display_text(self, p):
        display = ''
        lines_iterator = iter(p.stdout.readline, b"")
        for line in lines_iterator:
            if 'Active' in line:
                self.text.delete('1.0', END)
                self.text.insert(INSERT, display)
                display = ''
            display = display + line           


    def display_text2(self, p):
        while p.poll() is None:
            line = p.stdout.readline()
            if line != '':
                if 'Active' in line:
                    self.text.delete('1.0', END)
                self.text.insert(END, line)
                p.stdout.flush()       


    def execute(self):
            p = Popen(PROCESS,  universal_newlines=True,
                   stdout=PIPE, stderr=PIPE)
            print('process created with pid: {}'.format(p.pid))
            self.display_text(p)

  
if __name__ == "__main__":
    root = tk.Tk()
    root.title("netstat 1")
    Console(root).pack(expand=True, fill="both")
    root.mainloop()

Leave a Reply

Your email address will not be published. Required fields are marked *