1

我有一个 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())
4

4 回答 4

1

如果你使用subprocess.Popen你等待返回的处理程序.wait()。您可以使用 调查进程是否已完成 [和退出代码].poll()或与之交互(标准输入/输出).communicate()

该文档可在此处找到:http: //docs.python.org/2/library/subprocess.html#module-subprocess

你试过什么?

于 2013-06-15T19:21:48.140 回答
0

最后使用 GObject.timeout_add 解决了使用线程类中的变量更新消息的状态以了解进程何时完成,并且还使用.communicate()@johan-lundberg 建议的选项

于 2013-06-16T21:30:15.130 回答
0

至少有两个问题:

  • target=self.run_script()不正确:它立即运行该功能。Drop (),将方法作为参数传递而不是调用它。
  • self.event_info.set_label您在没有后台线程保护的情况下调用 GUI 方法 (on )。修复它的最简单方法是调用set_labelusing idle_add()

    Gobject.idle_add(self.event_info.set_label, msg) # in a background thread
    

    使用安全,idle_add因为Gobject.init_threads()模块顶部有。

另请参阅Gtk python 中的线程

我正在使用单独的线程来运行我的代码,但应用程序(或 UI)挂起。(gtk2)

于 2013-06-16T22:40:44.220 回答
0

我真的不确定它会有所帮助,但我建议你看看 Pexpect 模块: http: //pexpect.sourceforge.net/pexpect.html

据我了解,它是一个更复杂的系统调用“启动器”。

于 2013-06-16T16:06:14.023 回答