我正在Windows 7,64位,MSYS2 Mingw64 shell上进行测试(shell启动命令是C:msys64msys2_shell.cmd -use-full-path -mingw64
(;这里我通过pacman
安装:mingw-w64-x86_64-python2-2.7.13-1
,mingw-w64-x86_64-wxWidgets-3.0.2-17
和mingw-w64-x86_64-wxPython-3.0.2.0-6
。
考虑以下代码,它只有一个标题标签、按钮和目标标签;单击按钮时,标签应从"X"更改为"1":
import wx #, wx.html
import sys, os
from threading import Thread
# disable buffering (Windows)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
class Frame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.label = wx.StaticText(self, wx.ID_ANY, "Click the button to change label below: ")
self.bt_main = wx.Button(self, label="Click ME")
self.bt_main.Bind(wx.EVT_BUTTON, self.BtnClickHandler)
self.label2 = wx.StaticText(self, wx.ID_ANY, "XX")
sizer_vmain_app = wx.BoxSizer(wx.VERTICAL)
sizer_vmain_app.Add(self.label, proportion=0, flag=wx.EXPAND, border=0)
sizer_vmain_app.Add(self.bt_main, proportion=0, flag=0, border=0)
sizer_vmain_app.Add(self.label2, proportion=0, flag=0, border=0)
self.SetSizer(sizer_vmain_app)
self.Layout()
def BtnClickHandler(self, event):
testThread = Thread(target=self.DoBtnClick)
testThread.start()
testThread.join()
def DoBtnClick(self):
print("BtnClickHandler ")
myval = int("1")
self.label2.SetLabel(str(myval))
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
app_frame = Frame(None, wx.ID_ANY, "")
app.SetTopWindow(app_frame)
app_frame.Show()
app.MainLoop()
当我按原样运行此代码时,应用程序在涉及self.label2.SetLabel(str(myval))
时冻结。
但是,如果我避免线程,并改用此函数:
def BtnClickHandler(self, event):
# testThread = Thread(target=self.DoBtnClick)
# testThread.start()
# testThread.join()
self.DoBtnClick()
。然后一切正常。请注意,我通过在 MSYS2 Mingw64 shell 中运行python test.py
来调用此脚本。
那么,是否可以在Windows上使用线程运行此代码,如果是,如何运行?(否则,在 Linux 下使用线程运行它没有问题(
问题是wxWidgets库不是线程安全的。
这意味着您无法从辅助线程访问 GUI 元素。仅支持从主线程(在其上创建应用程序对象的线程(进行 GUI 访问。
不能从主线程以外的任何线程调用影响 GUI 的方法。相反,将事件发布到主线程,要求它代表工作线程执行所需的操作。
C++到目前为止,最简单的方法是将 CallAfter(( 与 lambda 一起使用,例如,您可以在线程代码中执行CallAfter([=](){ label2->SetLabel(myval); })
。不幸的是,我不知道这是否可以从Python获得。