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 ?
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()
This is an interesting solution. Would that be possible to have the whole working code?
I am asking because I was wonder how the while True
does not block the usability of the whole GUI... does it not?
As suspected, I tried and this example is not really work. If you use something like "ls -Rf /
" as command, you will see that the while loop will make the txt output flowing pretty well. However both windows (main and secondary) will block big time.
I suspect you need to send the print txt part in a separated thread or process. Or, if you use pygtk you can use stuff like
gobject.io_add_watch(self.ep1.stdout, # file descriptor
gobject.IO_IN, # condition
self.write_to_buffer ) # callback
which was actually invented for this.
Just in case someone else is looking for it...
log_box_1 = tk.Text(root, borderwidth=3, relief="sunken")
with subprocess.Popen("ls -la", shell=True, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
log_box_1.insert(tk.END, line)
From here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With