2013-05-09 17 views
2

我正在使用Python/wxWidgets編寫一個簡單的遊戲。使用線程控制wxPython中的UI元素

我已經寫了一個主窗口的類和一個簡單的類獲取用戶輸入的另一個框架。

我到目前爲止的體系結構是,該應用程序啓動並運行第二個運行稱爲「gameLogic」的函數的線程。主線程然後進入主應用程序循環。

gameLogic線程按順序運行,需要控制UI。例如,它需要打開一個以主框架作爲其父項的新對話框。但是,我發現這樣做最終會導致崩潰(足以導致OS X中的報告崩潰窗口)。

我一直在四處尋找和收集,我需要重構使用事件,但什麼我不知道如何做的是創建自己的事件。我可以讓我的gameLogic線程在主窗口中引發一個事件,然後調出輸入對話框並等待輸入(模態),然後將該數據返回給gameLogic線程。 gameLogic線程在等待時可能會阻塞,因爲UI線程是分開的。

在我的主框架的函數(事件處理程序),我可以創造一個輸入對話框的新實例,顯示它模態,然後獲得輸入。

我已經看到了實現這一點的各種想法,但一直沒能找到一個很好的例子來說明如何在我的wxFrame對象中創建自定義事件並從另一個線程調用它,邏輯線程塊並等待輸入回來,然後如何將輸入返回給gameThread。

忠告非常感謝!

+0

[此博客文章](http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/)顯示瞭如何創建和發送自定義事件(以及如何使用'CallAfter '和'發佈者',這對於簡單的情況通常更簡單)。至於有邏輯線程塊...如果你只是想阻塞,使用正常的線程同步;你不需要任何幻想。 – abarnert 2013-05-09 00:49:25

回答

1

首先,最困難的部分:

我見過各種各樣的實現這個想法,但一直沒能找到如何在我的wxFrame對象創建自定義事件一個很好的例子和從其他線程調用它

還有an example of this right on the wxPyWiki。您可能還想查看Working with wxPython in a separate thread的鏈接。

但是,我認爲博客文章wxPython and Threads從鼠標比。 Python解釋了最難的部分。並且它還向您展示了更簡單的方法(使用CallAfterPublisher代替張貼自定義事件),但我們堅持您提問的方式。

它唯一缺少的部分是:

...,也有邏輯線程塊,等到輸入回來,然後如何獲取輸入回gameThread。

但沒有什麼WX-spceific有關。向wx(或任何事件循環)發送信息的唯一原因是事件循環無法阻止。你的邏輯線程可以是塊,實際上應該是。所以,任何正常的線程同步機制都很好。

所以,你有一個線程願意永遠阻塞,直到值是準備好了,那希望能夠發送該值不阻塞另一個線程。您可以通過ConditionQueue輕鬆完成此操作。後者可能在這裏過度殺傷,但它更靈活,所以讓我們這樣做,只是爲了好玩。

我將以鼠標博客爲例,並且在每次後臺線程發佈EVT_RESULT事件時都會這樣做,然後它將阻塞,直到該事件得到處理,找回它可以...登錄的字符串,我想,這不是很有用,但我想表明它通過東西

from queue import Queue 
# ... 

class TestThread(Thread): 
# ... 
    def run(self): 
     for i in range(6): 
      # ... 
      wx.PostEvent(self.wxObject, ResultEvent(amtOfTime) 
      result_from_gui = self.wxObject.q.get(True, None) 
# ... 

class MyForm(wx.Frame): 
# ... 
    def __init__(self): 
     # ... 
     self.q = Queue() 
    # ... 
    def updateDisplay(self, msg): 
     # ... 
     t = msg.data 
     if isinstance(t, int): 
      text = "Time since thread started: %s seconds" % t 
     else: 
      text = "%s" % t 
      self.btn.Enable() 
     self.displayLbl.SetLabel(text) 
     self.q.put(text) 

在此示例中,GUI線程做self.q.put(text)updateDisplay結束。沒有什麼神奇的理由必須在那裏,然後 - 只要它最終發生(並且正好1次),邏輯線程將阻塞,直到它發生。例如,updateDisplay方法可以創建一個新按鈕,並在用戶單擊它時發送self.q.put(並刪除該按鈕)。

+0

這工作!我終於能夠創建一個自定義事件,並使用block = True的隊列來阻止等待返回,然後將所有這些包裝在一個簡單的函數中。完美的作品! – fdmillion 2013-05-09 01:19:01