Linux 无法初始化窗口并等待进程在Python 3+中结束;GTK&x2B;3.

Linux 无法初始化窗口并等待进程在Python 3+中结束;GTK&x2B;3.,linux,python-3.x,subprocess,gtk3,Linux,Python 3.x,Subprocess,Gtk3,我是面向对象编程、Python和GTK+3的新手,不过我对过程编程(主要是C)有相当的了解 我正在尝试构建一个简单的Python+GTK+3脚本,以便在Linux下运行pkexec apt get update 我有一个mainWindow类(基于Gtk.Window类),其中包含一个名为button(基于Gtk.button类)的按钮对象,该对象在单击的事件中触发新的更新窗口()方法 new\u update\u window()方法从updateWindow类(基于Gtk.window类)初

我是面向对象编程、Python和GTK+3的新手,不过我对过程编程(主要是C)有相当的了解

我正在尝试构建一个简单的Python+GTK+3脚本,以便在Linux下运行
pkexec apt get update

我有一个
mainWindow
类(基于
Gtk.Window
类),其中包含一个名为
button
(基于
Gtk.button
类)的按钮对象,该对象在
单击的
事件中触发
新的更新窗口()
方法

new\u update\u window()
方法从
updateWindow
类(基于
Gtk.window
类)初始化
updateWindow
对象,该类包含名为
label
(基于
Gtk.label
类)的标签对象,并调用方法
show\u all()
update()
updateWindow
中定义

update()
方法应该更改
label
,运行
pkexec apt get update
并再次更改
label

问题是无论我做什么,都会出现以下情况之一:

  • 如果我直接运行
    subprocess.Popen([“/usr/bin/pkexec”、“/usr/bin/apt get”、“update”])
    ,则会显示
    update.Window
    ,但
    label
    会立即设置为值,只有在
    pkexec apt get update
    完成执行后才应设置该值
  • 如果我直接运行
    子进程调用([“/usr/bin/pkexec”、“/usr/bin/apt get”、“update”])
    update.Window
    直到
    pkexec apt get update
    完成执行后才会显示
  • 我尝试了
    import
    ing
    threading
    ,在
    updateWindow
    中定义了一个单独的
    run\u update()
    方法,并使用
    thread=threading.thread(target=self.run\u update)
    thread.start()
    thread.join(),在单独的线程中启动函数,但是仍然取决于我在
    run\u update()
    subprocess.call()
    subprocess.Popen
    )中调用的方法,上面描述的相对行为会显示出来
Tl;博士 我无法理解如何实现我所追求的目标,即:

  • 显示
    updateWindow
    Gtk.Window
  • updateWindow
  • 正在运行
    pkexec apt get update
  • updateWindow
    • subprocess.Popen()
      update.Window
      显示,但
      label
      立即设置为只有在
      pkexec apt get update
      完成执行后才应设置的值
    • subprocess.call()
      update.Window
      直到
      pkexec apt get update
      完成执行后才会显示
    • 在函数中包装这两个函数并在单独的线程中运行函数不会改变任何事情
    这是代码

    不使用线程(情况1,在本例中使用
    subprocess.Popen()
    ):

    #/usr/bin/python3
    从gi.repository导入Gtk
    导入子流程
    类主窗口(Gtk.Window):
    定义初始化(自):
    Gtk.Window.\uuuu init\uuuu(self,title=“Updater”)
    button=Gtk.button()
    按钮。设置标签(“更新”)
    按钮。连接(“单击”,自我更新窗口)
    添加(按钮)
    def新建_更新_窗口(自身,按钮):
    update=updateWindow()
    update.show_all()
    update.update()
    类更新窗口(Gtk.Window):
    定义初始化(自):
    Gtk.Window.uu init_uuu(self,title=“更新…”)
    self.label=Gtk.label()
    self.label.set_文本(“空转…”)
    self.add(self.label)
    def更新(自我):
    self.label.set_文本(“正在更新…请稍候”)
    子进程调用([“/usr/bin/pkexec”、“/usr/bin/apt get”、“update”])
    self.label.set_文本(“已更新”)
    def运行_更新(自我):
    main=mainWindow()
    main.connect(“删除事件”,Gtk.main\u退出)
    main.show_all()
    Gtk.main()
    
    使用线程(案例3,在本例中使用
    subprocess.Popen()
    ):

    #/usr/bin/python3
    从gi.repository导入Gtk
    导入线程
    导入子流程
    类主窗口(Gtk.Window):
    定义初始化(自):
    Gtk.Window.\uuuu init\uuuu(self,title=“Updater”)
    button=Gtk.button()
    按钮。设置标签(“更新”)
    按钮。连接(“单击”,自我更新窗口)
    添加(按钮)
    def新建_更新_窗口(自身,按钮):
    update=updateWindow()
    update.show_all()
    update.update()
    类更新窗口(Gtk.Window):
    定义初始化(自):
    Gtk.Window.uu init_uuu(self,title=“更新…”)
    self.label=Gtk.label()
    self.label.set_文本(“空转…”)
    self.add(self.label)
    def更新(自我):
    self.label.set_文本(“正在更新…请稍候”)
    thread=threading.thread(目标=self.run\u更新)
    thread.start()
    thread.join()
    self.label.set_文本(“已更新”)
    def运行_更新(自我):
    subprocess.Popen([“/usr/bin/pkexec”,“/usr/bin/apt get”,“update”])
    main=mainWindow()
    main.connect(“删除事件”,Gtk.main\u退出)
    main.show_all()
    Gtk.main()
    
    中的

    您没有等待进程终止,请重试

    def run_update(self):
        proc = subprocess.Popen(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])
        proc.wait()
    
    相反。这应该正确地等待完成,但不会有多大帮助,因为
    updateWindow.update
    将从
    main窗口调用。new\u update\u窗口
    和GUI线程将等待进程完成

    subprocess.Popen
    subprocess.call启动的进程完成时,可以使用自定义信号进行通信:

    #!/usr/bin/python3
    
    from gi.repository import Gtk, GObject
    import threading
    import subprocess
    
    class mainWindow(Gtk.Window):
        def __init__(self):
            Gtk.Window.__init__(self, title = "Updater")
    
            button = Gtk.Button()
            button.set_label("Update")
            button.connect("clicked", self.new_update_window)
            self.add(button)
    
        def new_update_window(self, button):
            update = updateWindow(self)
            update.show_all()
            update.start_update()
    
    class updateWindow(Gtk.Window):
        def __init__(self, parent):
            Gtk.Window.__init__(self, title = "Updating...")
    
            self.label = Gtk.Label()
            self.label.set_text("Idling...")
            self.add(self.label)
            self.parent = parent
    
            GObject.signal_new('update_complete', self, GObject.SIGNAL_RUN_LAST,
                               None, (int,))
            self.connect('update_complete', self.on_update_complete)
    
        def on_update_complete(self, widget, rc):
            self.label.set_text("Updated {:d}".format(rc))
            # emit a signal to mainwindow if needed, self.parent.emit(...)
    
        def start_update(self):
            self.label.set_text("Updating... Please wait.")
            thread = threading.Thread(target=self.run_update)
            thread.start()
    
        def run_update(self):
            rc = subprocess.call(["/usr/bin/pkexec", "apt-get", "update"],
                                    shell=False)
            self.emit('update_complete', rc)
    
    main = mainWindow()
    main.connect("delete-event", Gtk.main_quit)
    main.show_all()
    Gtk.main()
    

    你就快到了…
    解决方案非常简单:)

    你遇到的问题是
    #!/usr/bin/python3
    
    from gi.repository import Gtk, GObject
    import threading
    import subprocess
    
    class mainWindow(Gtk.Window):
        def __init__(self):
            Gtk.Window.__init__(self, title = "Updater")
    
            button = Gtk.Button()
            button.set_label("Update")
            button.connect("clicked", self.new_update_window)
            self.add(button)
    
        def new_update_window(self, button):
            update = updateWindow(self)
            update.show_all()
            update.start_update()
    
    class updateWindow(Gtk.Window):
        def __init__(self, parent):
            Gtk.Window.__init__(self, title = "Updating...")
    
            self.label = Gtk.Label()
            self.label.set_text("Idling...")
            self.add(self.label)
            self.parent = parent
    
            GObject.signal_new('update_complete', self, GObject.SIGNAL_RUN_LAST,
                               None, (int,))
            self.connect('update_complete', self.on_update_complete)
    
        def on_update_complete(self, widget, rc):
            self.label.set_text("Updated {:d}".format(rc))
            # emit a signal to mainwindow if needed, self.parent.emit(...)
    
        def start_update(self):
            self.label.set_text("Updating... Please wait.")
            thread = threading.Thread(target=self.run_update)
            thread.start()
    
        def run_update(self):
            rc = subprocess.call(["/usr/bin/pkexec", "apt-get", "update"],
                                    shell=False)
            self.emit('update_complete', rc)
    
    main = mainWindow()
    main.connect("delete-event", Gtk.main_quit)
    main.show_all()
    Gtk.main()
    
    subprocess.call(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])
    
    self.label.set_text("Updated.")
    
    GObject.threads_init() 
    
    GObject.idle_add()
    
    #!/usr/bin/python3
    from gi.repository import Gtk, Gio
    
    # ...
    
    class updateWindow(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="Updating...")
    
            self.label = Gtk.Label()
            self.label.set_text("Idling...")
            self.add(self.label)
    
        def update(self):
            self.label.set_text("Updating... Please wait.")
            subprocess = Gio.Subprocess.new(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"], 0)
            subprocess.wait_check_async(None, self._on_update_finished)
    
        def _on_update_finished(self, subprocess, result):
            subprocess.wait_check_finish(result)
            self.label.set_text("Updated.")