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

kos*_*kos 5 linux subprocess python-3.x gtk3

我是面向对象编程、Python 和 GTK+3 的新手,尽管我对过程编程(主要是 C)有一定的了解。

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

我有一个mainWindow类(基于Gtk.Window类),其中包含一个名为button(基于Gtk.Button类)的按钮对象,该对象触发在事件中new_update_window()定义的方法;mainWindowclicked

new_update_window()方法updateWindow从一个updateWindow类(基于一个Gtk.Window类)初始化一个对象,该类包含一个名为label(基于一个Gtk.Label类)的标签对象,并调用方法show_all()update()定义在updateWindow;

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

问题是无论我做什么都会发生以下情况之一:

  • 如果我subprocess.Popen(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])直接运行,update.Window则显示但label立即设置为仅在pkexec apt-get update执行完成后才应设置的值;
  • 如果我subprocess.call(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])直接运行,update.Window则直到pkexec apt-get update执行完成才显示;
  • 我试图import荷兰国际集团threading,限定一个单独的run_update()在方法updateWindow和使用启动该功能在单独的线程thread = threading.Thread(target=self.run_update)thread.start()thread.join(),但仍取决于在该方法我呼叫run_update()subprocess.call()subprocess.Popen以上显示出)中所描述的相对行为。

Tl;博士

我不知道如何完成我所追求的目标,即:

  1. 显示updateWindow( Gtk.Window)
  2. 更新label( Gtk.Label)updateWindow
  3. 跑步 pkexec apt-get update
  4. 更新labelupdateWindow
  • subprocess.Popen():update.Window显示但label立即设置为仅在pkexec apt-get update完成执行后才应设置的值;
  • subprocess.call():update.Window直到pkexec apt-get update执行完成才显示;
  • 将两者中的任何一个包装在函数中并在单独的线程中运行该函数不会改变任何东西。

这是代码;

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

#!/usr/bin/python3
from gi.repository import Gtk
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()
        update.show_all()
        update.update()

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.call(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])
        self.label.set_text("Updated.")

    def run_update(self):

main = mainWindow()
main.connect("delete-event", Gtk.main_quit)
main.show_all()
Gtk.main()
Run Code Online (Sandbox Code Playgroud)

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

#!/usr/bin/python3
from gi.repository import Gtk
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()
        update.show_all()
        update.update()

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.")
        thread = threading.Thread(target=self.run_update)
        thread.start()
        thread.join()
        self.label.set_text("Updated.")

    def run_update(self):
        subprocess.Popen(["/usr/bin/pkexec", "/usr/bin/apt-get", "update"])

main = mainWindow()
main.connect("delete-event", Gtk.main_quit)
main.show_all()
Gtk.main()
Run Code Online (Sandbox Code Playgroud)

pto*_*ato 3

subprocess您可以使用Gio.Subprocess与 GTK 的主循环集成的模块,而不是使用 Python 的模块:

#!/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.")
Run Code Online (Sandbox Code Playgroud)