我正在尝试构建一个非常简单的wxPython图形用户界面,用于监视和显示外部数据。有一个按钮可以打开/关闭监控。当监控开启时,图形用户界面会用实时数据更新几个wx StaticLabels。关闭监视时,GUI会空闲。
我尝试用一个相当简单的Python Thread布局来构建它。当点击“开始监控”按钮时,程序会产生一个线程,用实时信息更新标签。当单击“停止监视”按钮时,将调用thread.join(),它应该会停止。
启动功能工作,实时数据更新工作很好,但当我点击‘停止’,整个程序冻结。我在64位的Windows7上运行此程序,因此得到通常的“此程序已停止响应”Windows对话框。
相关代码如下:
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线程还是相当陌生的,这是我想到的第一件事。
那么,为什么点击按钮来停止线程会让整个事情冻结呢?
发布于 2010-05-18 04:12:35
它可能挂在join([timeout])上,这会阻塞调用线程,直到其join()方法被调用的线程终止(正常终止或通过未处理的异常终止),或者直到发生可选的超时。
你的线程中是否有一些内部循环,或者是一个阻塞调用,它等待一些可能永远不会到来的数据源?当我写一个获取COM端口数据的基本串行程序时,它有时会挂起,因为我线程中的一个读取函数会阻塞,直到它得到一些东西。
我会稍微调试几个print语句,看看发生了什么。
编辑:
我还会使用threading.Event()而不是布尔标志,例如:
# 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()这应该不会使它的工作方式有所不同,但这是一种稍微安全一点的方法。
发布于 2010-05-18 04:46:31
在wxPython中,图形用户界面操作需要在主线程中进行。在代码中的某些地方,您正在从不同的线程调用GUI。
最简单的解决方案是使用wx.CallAfter()。一行代码将如下所示
wx.CallAfter(self.button.SetLabel, “Start Monitoring”)在函数完成后,它将从主线程调用self.button.SetLabel(“Start Monitoring”)。
还有其他方法可以解决这个问题,比如使用Python线程化队列或wx.PostEvent,但从CallAfter开始,因为它是最简单的。
其他问题也是相关的,比如你不能重启相同的线程,但是使用CallAfter的可以停止崩溃的。
发布于 2010-05-18 06:42:30
tom10在避免来自监视器线程的UI更新方面有正确的想法。
此外,在UI线程中使用阻塞调用self.monThread.join()可能也不是一个好主意。如果您希望UI提供一些关于监视器线程实际已结束的反馈,请让monThreadWorker在其关闭之前发出wx.CallAfter()或wx.PostEvent()。
避免UI线程中的任何阻塞,这样就避免了UI的死锁
https://stackoverflow.com/questions/2852124
复制相似问题