首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从wxPython图形用户界面按需启动/加入Python线程冻结

从wxPython图形用户界面按需启动/加入Python线程冻结
EN

Stack Overflow用户
提问于 2010-05-18 03:28:38
回答 3查看 3.2K关注 0票数 0

我正在尝试构建一个非常简单的wxPython图形用户界面,用于监视和显示外部数据。有一个按钮可以打开/关闭监控。当监控开启时,图形用户界面会用实时数据更新几个wx StaticLabels。关闭监视时,GUI会空闲。

我尝试用一个相当简单的Python Thread布局来构建它。当点击“开始监控”按钮时,程序会产生一个线程,用实时信息更新标签。当单击“停止监视”按钮时,将调用thread.join(),它应该会停止。

启动功能工作,实时数据更新工作很好,但当我点击‘停止’,整个程序冻结。我在64位的Windows7上运行此程序,因此得到通常的“此程序已停止响应”Windows对话框。

相关代码如下:

代码语言:javascript
复制
class MonGUI(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        ...
        ... other code for the GUI here ...
        ...
        # Create the thread that will update the VFO information
        self.monThread = Thread(None, target=self.monThreadWork)
        self.monThread.daemon = True
        self.runThread = False

    def monThreadWork(self):
        while self.runThread:
            ...
            ... Update the StaticLabels with info
            ... (This part working)
            ...

    # Turn monitoring on/off when the button is pressed.
    def OnClick(self, event):
        if self.isMonitoring:
            self.button.SetLabel("Start Monitoring")
            self.isMonitoring = False
            self.runThread = False
            self.monThread.join()
        else:
            self.button.SetLabel("Stop Monitoring")
            self.isMonitoring = True

            # Start the monitor thread!
            self.runThread = True
            self.monThread.start()

我确信有一种更好的方法可以做到这一点,但我对GUI编程和Python线程还是相当陌生的,这是我想到的第一件事。

那么,为什么点击按钮来停止线程会让整个事情冻结呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-05-18 04:12:35

它可能挂在join([timeout])上,这会阻塞调用线程,直到其join()方法被调用的线程终止(正常终止或通过未处理的异常终止),或者直到发生可选的超时。

你的线程中是否有一些内部循环,或者是一个阻塞调用,它等待一些可能永远不会到来的数据源?当我写一个获取COM端口数据的基本串行程序时,它有时会挂起,因为我线程中的一个读取函数会阻塞,直到它得到一些东西。

我会稍微调试几个print语句,看看发生了什么。

编辑:

我还会使用threading.Event()而不是布尔标志,例如:

代码语言:javascript
复制
# in the init code...
self.runThread = threading.Event()

# when starting thread...
self.runThread.set()
self.monThread.start()

# in the thread...
while self.runThread.isSet():
    pass # do stuff

# killing the thread...
self.runThread.clear()
self.monThread.join()

这应该不会使它的工作方式有所不同,但这是一种稍微安全一点的方法。

票数 1
EN

Stack Overflow用户

发布于 2010-05-18 04:46:31

在wxPython中,图形用户界面操作需要在主线程中进行。在代码中的某些地方,您正在从不同的线程调用GUI。

最简单的解决方案是使用wx.CallAfter()。一行代码将如下所示

代码语言:javascript
复制
wx.CallAfter(self.button.SetLabel, “Start Monitoring”)

在函数完成后,它将从主线程调用self.button.SetLabel(“Start Monitoring”)。

还有其他方法可以解决这个问题,比如使用Python线程化队列或wx.PostEvent,但从CallAfter开始,因为它是最简单的。

其他问题也是相关的,比如你不能重启相同的线程,但是使用CallAfter的可以停止崩溃的

票数 2
EN

Stack Overflow用户

发布于 2010-05-18 06:42:30

tom10在避免来自监视器线程的UI更新方面有正确的想法。

此外,在UI线程中使用阻塞调用self.monThread.join()可能也不是一个好主意。如果您希望UI提供一些关于监视器线程实际已结束的反馈,请让monThreadWorker在其关闭之前发出wx.CallAfter()或wx.PostEvent()。

避免UI线程中的任何阻塞,这样就避免了UI的死锁

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2852124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档