Mor*_*app 11 python multithreading wxpython
这是在wxPython的Phoenix分支中.
为了不阻止GUI,我试图运行一些线程.
我的两个线程工作正常,但另一个线程似乎永远不会达到其绑定结果函数.我可以告诉它正在运行,它似乎没有正确发布事件.
这是主计算线程的结果函数:
def on_status_result(self, event):
if not self.panel.progress_bar.GetRange():
self.panel.progress_bar.SetRange(event.data.parcel_count)
self.panel.progress_bar.SetValue(event.data.current_parcel)
self.panel.status_label.SetLabel(event.data.message)
Run Code Online (Sandbox Code Playgroud)
这是我绑定他们的方式:
from wx.lib.pubsub.core import Publisher
PUB = Publisher()
Run Code Online (Sandbox Code Playgroud)
这是我绑定方法的方式:
def post_event(message, data):
wx.CallAfter(lambda *a: Publisher().sendMessage(message, data=data))
Run Code Online (Sandbox Code Playgroud)
这是线程.第一个不起作用,但后两个做:
class PrepareThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = False
def run(self):
while not self._want_abort:
for status in prepare_collection(DATABASE, self._previous_id, self._current_id, self._year, self._col_type,
self._lock):
post_event('prepare.running', status)
post_event('prepare.complete', None)
return None
def abort(self):
self._want_abort = True
class SetupThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = False
def run(self):
while not self._want_abort:
do_more_stuff_with_the_database()
return None
def abort(self):
self._want_abort = True
class LatestCollectionsThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = False
def run(self):
while not self._want_abort:
do_stuff_with_my_database()
return None
def abort(self):
self._want_abort = True
Run Code Online (Sandbox Code Playgroud)
prepare_collection
是一个产生如下所示Status
对象的函数:
class Status:
def __init__(self, parcel_count, current_parcel, total, message):
self.parcel_count = parcel_count
self.current_parcel = current_parcel
self.total = total
self.message = message
Run Code Online (Sandbox Code Playgroud)
以下是我创建/启动/订阅PrepareThread的方法:
MainForm(wx.Form):
prepare_thread = PrepareThread(self)
prepare_thread.start()
self.pub = Publisher()
self.pub.subscribe(self.on_status_result, 'prepare.running')
self.pub.subscribe(self.on_status_result, 'prepare.complete')
def on_status_result(self, event):
if not self.panel.progress_bar.GetRange():
self.panel.progress_bar.SetRange(event.data.parcel_count)
self.panel.progress_bar.SetValue(event.data.current_parcel)
self.panel.status_label.SetLabel(event.data.message)
Run Code Online (Sandbox Code Playgroud)
我已经尝试过prepare_collection
使用range(10)
,但我仍然没有遇到事件处理程序.
这可能是一个相当复杂的答案,并且很难准确地计算出代码的每个部分中有哪些片段(即它们都位于哪些文件中)。我假设您想保留pubsub
执行此操作的方法(我认为这是一个好主意)。如果您的真实项目的结构非常复杂,您可能需要比Publisher
我在这里使用的更复杂的管理 - 让我知道......
这里 - 我将先剧透 - 这是一个您似乎想要的单文件解决方案- 一个带有按钮的面板,用于在准备完成时启动准备线程、状态栏和处理程序。使用 wxPython Phoenix 64 位 Python 3 和 Python 2.7 上的老式 wxPython 进行测试。两者都在 Windows 上运行 - 但如果需要的话我可以在 Linux 机器上运行它。
总结该文件的重要(非样板)部分
您需要一个Publisher
对象,您的线程向其发送消息并且您的主线程(MainForm
我猜在您的示例中)订阅该对象。您可以为每个线程管理一个Publisher
,但我认为这里您只需要一个PrepareThread
,所以我现在将使用该模型。
在文件的顶部,使用
from wx.lib.pubsub import pub
Run Code Online (Sandbox Code Playgroud)
这可以pubsub
管理实例化单个Publisher
对象。
在您的线程中,正如您所做的那样,在那里发布消息 - 对您的帮助程序稍作修改post_event
:
def post_event(message, data):
wx.CallAfter(lambda *a: pub.sendMessage(message, data=data))
Run Code Online (Sandbox Code Playgroud)
在您的主线程中 - 订阅这些消息。我想说,通常最简单的是每条消息都有一个处理程序,而不是像您一样向同一个处理程序发送两条不同的消息,所以我选择了
pub.subscribe(self.on_status_result, 'prepare.running')
pub.subscribe(self.on_status_finished, 'prepare.complete')
Run Code Online (Sandbox Code Playgroud)
您可以保持on_status_result
原样并定义类似的on_status_finished
. 在我的示例中,我稍后启用了一个新按钮,让您可以完成一些实际工作。
注意,在命名消息的有效负载时,您需要小心 -pubsub
推断出大量有关其期望的信息,这首先吸引了我。
PS 就在准备这个答案的最后 - 我发现了这篇博文。它说的内容与我上面的内容类似,所以我不会重现它,但他们使用另一种实例化方法,Publisher()
就像你原来的例子一样——这意味着这也应该有效。您可能更喜欢那里的措辞。同样 - 您可能会发现这个 wxPython wiki页面很有用。
归档时间: |
|
查看次数: |
591 次 |
最近记录: |