我有一个python程序,当我在一个线程中运行一个bash脚本并显示一些消息时,我想要一个进度条脉动。
当我单击一个按钮时,线程开始启动脚本,但消息和进度条仅在线程完成时响应,仅显示最后一条消息。
阅读,我明白我阻止了主循环,但我无法弄清楚如何解决这个问题。
我的程序的简化代码,问题是在调用“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())
答案 0 :(得分:1)
如果您使用subprocess.Popen
,则等待返回的处理程序.wait()
。您可以使用.poll()
调查流程是否已完成[和退出代码],或与.communicate()
进行交互(标准输入/输出)。
文档可在此处找到: http://docs.python.org/2/library/subprocess.html#module-subprocess
你试过什么?答案 1 :(得分:0)
我真的不确定它会有所帮助,但我建议你看一下Pexpect模块:http://pexpect.sourceforge.net/pexpect.html
据我所知,它是系统调用的更复杂的“启动器”。
答案 2 :(得分:0)
最后使用GObject.timeout_add解决了使用线程类中的变量更新消息状态以了解进程何时完成,以及使用@ johan-lundberg建议的.communicate()
选项
答案 3 :(得分:0)
至少有两个问题:
target=self.run_script()
不正确:它立即运行该功能。删除()
,将方法作为参数传递而不是调用它。您在没有后台线程保护的情况下调用GUI方法(在self.event_info.set_label
上)。解决此问题的最简单方法是使用set_label
调用idle_add()
:
Gobject.idle_add(self.event_info.set_label, msg) # in a background thread
使用idle_add
是安全的,因为模块顶部有Gobject.init_threads()
。
I am using a separate thread to run my code, but the application (or the UI) hangs.(gtk2)