【问题标题】:using threads with wxPython correctly正确使用 wxPython 线程
【发布时间】:2015-05-07 00:34:11
【问题描述】:

我正在使用 wxPython 构建我的程序的 GUI,我无法运行一个函数,该函数使用线程从文件中获取数据并将其显示在 ObjectListView 中,从文件中读取数据运行良好但显示来自线程的数据有时会使整个程序崩溃。 gui.ProgressDialog 是一个 wx.Frame,它将显示进度条,直到线程完成。 self.dv 是一个 ObjectListView,一个从 wx.ListCtrl 派生的对象,set_data 是我写的一个函数,它遍历数据并将其添加到列表中。

def set_data(self,data):
    """set the data on the ObjectListView"""
    pd = gui.ProgressDialog("Setting Data..")
    def set_thread():
        self.dv.set_data(data) #Takes time
        pd.Close()

    #opens a thread that sets the data
    t = Thread(target = set_thread,name="SetDataThread")
    t.start()

我读过一些关于wx.CallAfter 的内容,我应该使用它,但我不明白如何使用。我试着像这样调用 set_data - wx.CallAfter(self.dv.set_data,data) 但它也不起作用。有人可以解释函数 wx.CallAfterwx.CallLaterwx.PostEvent ,在使用 wxPython 线程时它们有什么帮助,我应该使用哪一个?或其他解决方案?

【问题讨论】:

  • 除了更大的问题之外,您至少在一个函数调用上去掉了括号,这意味着进度对话框永远不会关闭……
  • 什么是self.dv,它的set_data 有什么作用?

标签: python multithreading wxpython


【解决方案1】:

您不能从辅助线程进行任何 GUI 调用。这在 wx.Thread 文档中进行了解释,但它也适用于普通 Python threading.Thread 线程:

GUI 调用,例如对 wxWindow 或 wxBitmap 的调用在辅助线程中根本不安全,可能会过早结束您的应用程序。

因此,您要做的就是向主线程发送一条消息,要求它为您进行 GUI 调用。

PostEvent 是低级解决方案。您创建了一种新的事件。您在主线程上为该事件类型编写一个处理程序,该处理程序根据事件中的信息执行一些 GUI 工作。然后在您的后台线程上,您使用适当的信息构造其中一个事件,然后 PostEvent 将其放入主线程的消息队列中。

其他选项基本上是围绕它的更高级别的包装器。 CallAfter 可能就是你想要的那个。 wxPyWiki 上的CallAfter 页面有很好的解释和完整的示例,文档页面本身也有一个很好的示例,所以我不会尝试与他们竞争;相反,我会尝试回答您的具体问题。

我认为您缺少的是关键是将 GUI 调用推送到主线程。所有 GUI 调用,没有其他调用。

我不知道self.dv 是什么,但它看起来不像wx GUI 对象(它具有Python 风格的set_data 方法,而不是wx 风格的SetData) .当然,如果它在多个线程之间共享,并且不是自同步的,那么您几乎肯定需要一个 Lock 或其他同步对象来保护它。但你不需要,也不想在这里CallAfter

另一方面,pd.Close 是一个 GUI 调用。 (好吧,如果你记得括号的话。)你肯定需要CallAfter

所以:

def set_data(self,data):
    """set the data on the ObjectListView"""
    pd = gui.ProgressDialog("Setting Data..")
    def set_thread():
        data = takes_time()
        with self.dv_lock:
            self.dv.set_data(data)
        wx.CallAfter(pd.Close)

    #opens a thread that sets the data
    t = Thread(target = set_thread,name="SetDataThread")
    t.start()

您还询问了CallLater。当您希望某些代码在 X 毫秒后在主线程上运行时,您可以使用它,而不是尽快。虽然您可以使用 CallLater(0, pd.Close) 代替 CallAfter(pd.Close),但没有充分的理由这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-04
    相关资源
    最近更新 更多