我想在控制台会话的同时使用交互式wxPython GUI(如交互模式下的matplotlib)。这要求控制台继续在线程 0 上运行,并且所有 wx 交互都在单独的线程上运行。(我很清楚只有一个线程应该访问wx。
我下面的演示代码可以工作(通过python -i
启动时),但是当我退出Python(例如通过exit()
)时弹出wxWidgets调试警报(看起来像崩溃对话框)。当 wx 主线程不是线程 0 时,如何避免退出 Python 时的警报?
import threading
class GUI(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
def run(self):
import wx
app = wx.App()
window = wx.Frame(None, title="Hello World!", size=(200, 100))
panel = wx.Panel(window)
text = wx.StaticText(panel, label="Hello World!", pos=(0, 0))
window.Show(True)
app.MainLoop()
gui_thread = GUI()
gui_thread.start()
其他人报告说,在旧版本的wxPython中使用这样的策略取得了成功,但是他们的代码(案例3)在关闭时给了我与上述相同的崩溃。
我在退出时遇到的错误(可能来自自动注册的atexit
处理程序?)与您尝试从第二个线程访问 wx 时得到的错误相同:assert "wxIsMathThread()" failed in wxSocketBase::IsInitialized(): unsafe to call from other threads [in thread 1b68]
.
具体来说,当使用Anaconda Python 3.6.3在Windows 10上运行wxPython 4.0.1(又名Phoenix)时,我会收到wxWidgets调试警报。我还没有测试其他平台和版本。
警报来自通过导入wx
自动插入的atexit
处理程序。为了避免这种情况,同时仍然允许例程调试,可以在加载wx
后禁用警报atexit
:
import threading
import atexit
class GUI(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
def run(self):
import wx
atexit.register(disable_asserts)
app = wx.App()
window = wx.Frame(None, title="Hello World!", size=(200, 100))
panel = wx.Panel(window)
text = wx.StaticText(panel, label="Hello World!", pos=(0, 0))
window.Show(True)
app.MainLoop()
def disable_asserts():
import wx
wx.DisableAsserts()
gui_thread = GUI()
gui_thread.start()