Reputation: 171
i am writing a graphical shell for a command-line program in python using GTK. The main program has output like this:
Starting Tractor:
Dec 04 22:10:34.000 [notice] Bootstrapped 0%: Starting
Dec 04 22:10:34.000 [notice] Bootstrapped 80%: Connecting to the Tor network
Dec 04 22:10:35.000 [notice] Bootstrapped 85%: Finishing handshake with first hop
Dec 04 22:10:36.000 [notice] Bootstrapped 90%: Establishing a Tor circuit
Dec 04 22:10:37.000 [notice] Bootstrapped 100%: Done
Tractor is conneted.
I have a start button which starts the program via subprocess. since I want the main window to be operative during the start process, I used thrading for that. Here is my code:
def on_start_clicked(self, button):
spinner = Gtk.Spinner()
self.props.icon_widget = spinner
spinner.start()
self.show_all()
header_bar = self.get_parent()
if self.is_running():
def task_thread():
task = Popen(command + "stop", stdout=PIPE, shell=True)
task.wait()
spinner.stop()
header_bar.show_progress_button(False)
self.update_label()
else:
def task_thread():
header_bar.show_progress_button(True)
task = Popen(command + "start", stdout=PIPE, shell=True)
while True:
output = task.stdout.readline().decode("utf-8")
if output == '' and task.poll() is not None:
break
if output and '%' in output:
print(output.split()[5][:-2])
task.wait()
spinner.stop()
self.update_label()
thread = Thread(target=task_thread)
thread.daemon = True
thread.start()
The problem is that the log output is not realtime, but it waits until the whole process to be complete and then prints the whole output altogether!
I want the actual percentage at the time, in order to pass it to a progress bar, showing how much of the task is done. How can I accomplish that?
I changed the code as following thanks to theGtknerd, but the feed function still works after the process is done and just prints the first line of the whole output. I think here is a malfunction in when IO_IN is triggered.
def thread_finished (self, stdout, condition):
GLib.source_remove(self.io_id)
stdout.close()
self.spinner.stop()
self.update_label()
print("heeey")
return False
def feed (self, stdout, condition):
line = stdout.readline()
line = line.decode("utf-8")
print(line)
return True
def on_start_clicked(self, button):
self.spinner = Gtk.Spinner()
self.props.icon_widget = self.spinner
self.spinner.start()
self.show_all()
header_bar = self.get_parent()
if self.is_running():
header_bar.show_progress_button(False)
task = Popen(command + "stop", stdout=PIPE, shell=True)
else:
header_bar.show_progress_button(True)
task = Popen(command + "start", stdout=PIPE, shell=True)
self.io_id = GLib.io_add_watch(task.stdout, GLib.IO_IN, self.feed)
GLib.io_add_watch(task.stdout, GLib.IO_HUP, self.thread_finished)
Upvotes: 3
Views: 556
Reputation: 3745
Here is a small example for you to learn from. So in my Python file I have:
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, GObject
from subprocess import Popen, PIPE, STDOUT
import os, sys
class GUI:
def __init__(self):
window = Gtk.Window()
self.label = Gtk.Label()
window.add(self.label)
window.show_all()
window.connect("destroy", self.on_window_destroy)
p = Popen(['./long_run.sh'], stdout = PIPE,stderr = STDOUT,stdin = PIPE)
self.io_id = GObject.io_add_watch(p.stdout, GObject.IO_IN, self.feed)
GObject.io_add_watch(p.stdout, GObject.IO_HUP, self.thread_finished)
def feed (self, stdout, condition):
line = stdout.readline()
line = line.decode(encoding="utf-8", errors="strict")
self.label.set_label(line)
return True
def thread_finished (self, stdout, condition):
GObject.source_remove(self.io_id)
stdout.close()
self.label.set_label("Hurray, all done!")
def on_window_destroy(self, window):
Gtk.main_quit()
print ("shutdown")
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
And in the file long_run.sh I have:
#!/bin/bash
echo "Loading, please wait..."
sleep 5
echo "10%"
sleep 5
echo "20%"
sleep 5
echo "30%"
sleep 5
echo "40%"
sleep 5
echo "50%"
sleep 5
echo "60%"
sleep 5
echo "70%"
sleep 5
echo "80%"
sleep 5
echo "90%"
sleep 5
echo "100%"
sleep 5
Upvotes: 1