ericc ericc - 1 month ago 20
Python Question

Display realtime output of a subprocess in a tkinter widget

My question is almost the same as this one:
Widget to Display subprocess stdout?
but a step further.

I have the following code (python2.7):

def btnGoClick(p1):
params = w.line.get()
if len(params) == 0:
return

# create child window
win = tk.Toplevel()
win.title('Bash')
win.resizable(0, 0)
# create a frame to be able to attach the scrollbar
frame = ttk.Frame(win)
# the Text widget - the size of the widget define the size of the window
t = tk.Text(frame, width=80, bg="black", fg="green")
t.pack(side="left", fill="both")
s = ttk.Scrollbar(frame)
s.pack(side="right", fill="y")
# link the text and scrollbar widgets
s.config(command=t.yview)
t.config(yscrollcommand=s.set)
frame.pack()

process = subprocess.Popen(["<bashscript>", params], shell=False,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

while True:
out = process.stdout.readline()
if out == '' and process.poll() is not None:
break
print out
t.insert(tk.END, out)


The output from the "longrunning" bash script is captured in realtime (appear in the console) but the Tkinter window appear only after the end of the subprocess !!

How can I have the window appearing before the subprocess start and update its content in realtime ?

Answer

Finally I found the solution. After the window construction, you must add :

frame.pack()
# force drawing of the window
win.update_idletasks()

And then after every line insertion in the widget, you must also force a refresh with the same method only on the widget.

# insert the line in the Text widget
t.insert(tk.END, out)
# force widget to display the end of the text (follow the input)
t.see(tk.END)
# force refresh of the widget to be sure that thing are displayed
t.update_idletasks()
Comments