2017-04-11 38 views
0

我在Windows 7,64位,MSYS2 Mingw64殼(殼開始命令是C:\msys64\msys2_shell.cmd -use-full-path -mingw64)測試;這裏我已經通過pacman安裝:mingw-w64-x86_64-python2-2.7.13-1,mingw-w64-x86_64-wxWidgets-3.0.2-17mingw-w64-x86_64-wxPython-3.0.2.0-6在MSYS2中的wxPython:線程處理程序中的SetLabel導致凍結?

考慮這個代碼,其中只有一個標題標籤,按鈕和目標標籤;點擊按鈕時,標籤應改變從「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下使用線程運行它沒有問題)

+1

你看過wxpython演示嗎? – Igor

+0

謝謝@Igor - 不,我沒有,它有什麼不同?這對我有何幫助? – sdaau

+0

對不起我的壞。請參閱下面的答案。 – Igor

回答

0

問題是wxWidgets庫不是線程安全的。

它的意思是,你不能從輔助線程訪問GUI元素。只有主線程支持GUI訪問 - 您在其上創建應用程序對象。

0

不能調用影響來自除主之外的任何線程圖形用戶界面的方法。相反,將事件發佈到主線程,請求它代表工作線程執行所需的操作。

在C++中做到這一點的最簡單的方法,到目前爲止,是使用與CallAfter()的λ,例如你可以在線程代碼中執行CallAfter([=](){ label2->SetLabel(myval); })。不幸的是,我不知道這是否可以從Python獲得。

相關問題