我正在使用Python / wxWidgets编写一个简单的游戏。
我为主窗口编写了一个类,为另一个用户输入的框架编写了一个简单的类。
我到目前为止的架构是应用程序启动并运行第二个线程,运行一个名为“gameLogic”的函数。然后主线程进入主应用程序循环。
gameLogic线程按顺序运行,需要控制UI。例如,它需要打开一个以主框架为父框架的新对话框。但是,我发现这样做最终导致崩溃(足以在OS X中弹出报告崩溃窗口)。
我一直在环顾四周并收集我需要重构以使用事件,但我不确定如何做的是创建我自己的事件。我可以让我的gameLogic线程在主窗口中引发一个事件,然后调出输入对话框并等待输入(模态)然后将该数据返回给gameLogic线程。 gameLogic线程可以在等待时阻塞,因为UI线程是独立的。
在我的主框架中的一个函数(事件处理程序)中,我可以创建一个输入对话框的新实例,以模态方式显示它,然后获取输入。
我已经看到了实现这个的各种想法但是却找不到如何在我的wxFrame对象中创建自定义事件并从另一个线程调用它的好例子,并且还有逻辑线程阻塞并等待输入返回,然后如何将输入返回到gameThread。
建议非常感谢!
答案 0 :(得分:1)
首先,困难的部分:
我已经看到了实现这一点的各种想法,但未能找到如何在我的wxFrame对象中创建自定义事件并从其他线程调用它的好例子
有an example of this right on the wxPyWiki。您可能还想查看Working with wxPython in a separate thread的链接。
但是,我认为来自The Mouse Vs的博文wxPython and Threads。 Python最好地解释了最难的部分。它还向您展示了更简单的方法(使用CallAfter
和Publisher
而不是发布自定义事件),但让我们坚持您提出的方式。
唯一缺少的是:
...还有逻辑线程阻塞并等待输入返回,然后如何将输入返回到gameThread。
但是没有什么特别的。将信息发送到wx(或任何事件循环)的唯一原因是事件循环无法阻塞。您的逻辑线程可以阻止,实际上应该。所以,任何正常的线程同步机制都可以。
所以,你有一个线程想要永远阻塞,直到一个值准备就绪,另一个线程想要能够在不阻塞的情况下发送该值。您可以使用Condition
或Queue
轻松完成此操作。后者在这里可能有些过分,但它更灵活,所以让我们这样做,只是为了好玩。
我将从鼠标博客中获取示例,并且每次后台线程发布EVT_RESULT
事件时都会这样做,然后阻塞直到该事件被处理,返回它可以的字符串... log或者其他什么,我猜,它不是很有用,但我想通过传递来表明它。
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
(并删除按钮)。