Using tkinter and python to continuously display the output from a system command
Publish date: Jun 24, 2018
Last updated: Jan 24, 2023
Last updated: Jan 24, 2023
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()