在 PyGObject 内省中,带有 Python 的 GTK 中的线程是不是发生了变化?

Posted

技术标签:

【中文标题】在 PyGObject 内省中,带有 Python 的 GTK 中的线程是不是发生了变化?【英文标题】:Has threading in GTK w/ Python changed in PyGObject introspection?在 PyGObject 内省中,带有 Python 的 GTK 中的线程是否发生了变化? 【发布时间】:2011-10-20 01:30:08 【问题描述】:

我第一次将程序从 PyGTK 转换为 PyGObject 内省,我遇到了线程障碍。我有一个需要一些时间才能完成的过程,所以我弹出一个带有进度条的对话框,我使用一个线程来完成这个过程并更新进度条。这在 PyGTK 上运行良好,但在转换为 PyGObject 后,我​​得到了所有通常不正确的线程怪异:程序挂起,但它似乎挂在进程的不同部分,等等。所以我觉得有些东西已经改变了,但我可以不知道是什么。

这是一个简单的 PyGTK 进度条示例:http://aruiz.typepad.com/siliconisland/2006/04/threads_on_pygt.html 如该页面所示,该代码有效。我已经将它转换为 PyGObject 内省,我遇到了与我的程序相同的问题:它挂起,它没有正确更新进度条等。

import threading
import random, time
from gi.repository import Gtk, Gdk
#Initializing the gtk's thread engine
Gdk.threads_init()


class FractionSetter(threading.Thread):
    """This class sets the fraction of the progressbar"""

    #Thread event, stops the thread if it is set.
    stopthread = threading.Event()

    def run(self):
        """Run method, this is the code that runs while thread is alive."""

        #Importing the progressbar widget from the global scope
        global progressbar 

        #While the stopthread event isn't setted, the thread keeps going on
        while not self.stopthread.isSet() :
            # Acquiring the gtk global mutex
            Gdk.threads_enter()
            #Setting a random value for the fraction
            progressbar.set_fraction(random.random())
            # Releasing the gtk global mutex
            Gdk.threads_leave()

            #Delaying 100ms until the next iteration
            time.sleep(0.1)

    def stop(self):
        """Stop method, sets the event to terminate the thread's main loop"""
        self.stopthread.set()

def main_quit(obj):
    """main_quit function, it stops the thread and the gtk's main loop"""
    #Importing the fs object from the global scope
    global fs
    #Stopping the thread and the gtk's main loop
    fs.stop()
    Gtk.main_quit()

#Gui bootstrap: window and progressbar
window = Gtk.Window()
progressbar = Gtk.ProgressBar()
window.add(progressbar)
window.show_all()
#Connecting the 'destroy' event to the main_quit function
window.connect('destroy', main_quit)

#Creating and starting the thread
fs = FractionSetter()
fs.start()

Gtk.main()

在 Gdk 线程功能的文档中,它强调在运行 gdk_threads_init() 之前必须先运行 g_thread_init(NULL)。但是要运行它,您需要链接一些额外的库。如果我尝试通过自省导入 GLib,然后尝试运行 GLib.thread_init(),则会收到以下错误:

>>> from gi.repository import GLib
>>> GLib.thread_init(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/gi/types.py", line 44, in function
    return info.invoke(*args)
glib.GError: Could not locate g_thread_init: `g_thread_init': /usr/lib/libglib-2.0.so.0: undefined symbol: g_thread_init

我认为这是因为没有链接额外的线程库。如果这是我的线程问题的原因,我该如何使用 GLib,就好像这些库已经链接一样?

【问题讨论】:

你不应该用Gdk.threads_enter()Gdk.threads_leave() 包装对Gtk.main() 的调用吗?我见过的所有 C 代码示例都是这样做的。例如:blogs.operationaldynamics.com/andrew/software/gnome-desktop/… 【参考方案1】:

我通过浏览一些用 Python 编写的 Gnome 程序(在本例中是 Gnome Sudoku,实际上帮助了我几次),设法回答了我自己的问题。

诀窍是您必须在代码开头调用 GObject.threads_init(),而不是 C 文档所暗示的 GLib.thread_init()

【讨论】:

我只想说声谢谢。伙计,使用这些东西需要 90% 的谷歌搜索。 非常感谢!我遇到了这个确切的问题,不知道我哪里出错了。我希望 PyGObject 有一些特定的文档,而不仅仅是“检查 C 文档” 对此答案的现代更新:GObject.threads_init() 和 GLib.threads_init() 是同义词,在 PyGObject v3.10.2 及更高版本中实际上都不需要。另见:wiki.gnome.org/Projects/PyGObject/Threading @SimonFeltman 另外,在现代 GTK 中,人们会完全放弃使用 Gdk.threads_enter()Gdk.threads_leave(),并使用像 idle_add(lambda: progressbar.set_fraction(random.random())) 这样的调用来运行实际运行线程中的所有 GUI 代码主循环。其他任何事情都会导致崩溃和头痛。

以上是关于在 PyGObject 内省中,带有 Python 的 GTK 中的线程是不是发生了变化?的主要内容,如果未能解决你的问题,请参考以下文章

python SITCON 2018中使用的PyGObject示例。

使用 Pygobject 和 Python 3 从内存数据中显示图像

如何使用 Python 2.6 在 Windows 上安装 PyGTK / PyGobject?

用 pygobject 编写 D-Bus 服务?

PyGObject GTK+ 3 - 文档?

在 virtualenv 中通过 pip 安装 PyGObject [重复]