I have a python programm that I want a progressbar to be pulsed when I run a bash script in a thread and show some messages.
When I click a button, the thread is started launching the script, but the messages and progressbar only gets responsive when the thread is finished, showing only the last message.
Reading, I understood that I'm blocking the main loop but I can't figure it out how to solve this.
Simplified code of my program, the problem is when calling "on_fixme_button_pressed":
from gi.repository import Gtk, Gdk, Pango, GObject, GLib
import os, sys
import xml.etree.ElementTree as etree
from urllib.request import urlopen
from subprocess import Popen
import threading
UI_FILE = "remendo_gtk.ui"
#UI_FILE = "/usr/local/share/remendo_gtk/ui/remendo_gtk.ui"
GObject.threads_init()
class GUI:
def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file(UI_FILE)
self.builder.connect_signals(self)
self.window = self.builder.get_object('remendo')
self.event_treeview = self.builder.get_object('event_treeview')
self.event_info = self.builder.get_object('event_info')
self.progressbar = self.builder.get_object('progressbar')
self.progressbar_lock = threading.Lock()
self.selected_event = ''
self.url_script = ''
self.local_script = ''
self.window.connect("destroy", lambda _: Gtk.main_quit())
self.set_event_list()
self.window.show_all()
def pulse_progressbar(self):
if threading.active_count() > 1:
self.progressbar.pulse()
return True
self.progressbar.set_fraction(0.0)
self.progressbar_lock.release()
return False
def on_fixme_button_clicked(self, button):
self.event_info.set_label("Fixing now...")
script = threading.Thread(target=self.run_script(), args=(self,))
script.start()
if self.progressbar_lock.acquire(False):
GLib.timeout_add(250, self.pulse_progressbar)
def run_script(self):
try:
self.local_script = '/tmp/%s.sh' % self.selected_event.replace(" ", "_")
script = urlopen(self.url_script)
localscript = open(self.local_script, 'wb')
localscript.write(script.read())
localscript.close()
command = ['bash', self.local_script]
p = Popen(command)
p.communicate()
#self.event_solved()
self.event_info.set_label("My work is done. Good day!")
except:
self.event_info.set_label("Script failed: %s" % self.local_script)
return False
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
Popenisn't a regular function, but rather a constructor. If you want to do anything with the process you opened, you'll need to store its return-value in a variable that you can interact with and call methods on (such aswait)..communicate()seems to work just writtingp=Popen(command)and thenp.communicate(), but for some reason the popup window doesn't show up until the command ends, showing the "My work is done" messagecommunicatemethod, since by definition it blocks until the process is complete (or, as the docs put it: "Wait for process to terminate"). What you need to do is, read the documentation. Or heck, just read the answer that you already replied to: Johan Lundberg already told you that to investigate if the process has completed, you use thepollmethod.