【问题标题】:Threading in wxpythonwxpython中的线程
【发布时间】:2015-09-05 06:51:37
【问题描述】:

您好,我是 python 新手,已经开始使用 wxpython 开发 GUI。我只是想知道wxpython中的基本线程操作。我有一个具有 OK 和 Cancel 按钮的主进程和一个从 main 派生的具有 OK 和 Cancel 按钮的子进程。我想实现线程这样的方式,即单击主进程上的确定按钮必须向子进程发送消息,并且子进程必须查找它的任何进程是否正在运行,如果是,它必须等待该进程完成然后从主进程接收消息。与主进程中的取消按钮类似。 基本上我想看看子进程如何从主进程接收消息并且两者并行工作。 我正在尝试使用 wx.CallAfter 和 wx.PostEvent,但我对这里的线程概念感到困惑。请有人帮助我。 提前致谢

【问题讨论】:

标签: python-2.7 wxpython python-multithreading


【解决方案1】:

wxpython 中的多线程与 python 没有什么不同。 wx.CallAfter and threading example 显示了您如何使用两者。 wx.CallAfter 等待事件完成并在主线程中运行处理程序。此外,您可以使用计时器 (wx.Timer) 来检查子进程和发送/接收数据。

这里是wx.PostEvent 的链接,展示了如何使用它。在此示例中,您创建自定义事件,将其绑定到主线程中的处理程序。之后,您在工作线程中发布事件并附加一些数据。您的事件处理程序接收事件并在主线程中执行一些操作。

所以,在使用多线程时会出现一些重要问题

  1. 何时启动子线程,
  2. 线程之间使用哪种通信机制,
  3. 如何在必要时以安全的方式停止线程,

等等

我更喜欢 wx.Timer + Queue 模块。我可以定期使用计时器或用户事件检查队列,并通过队列发送一些东西(即无)以停止线程。

注意:主线程中长时间运行的作业会导致 GUI 无响应。

【讨论】:

  • 我尝试了上面的代码,但我无法得到预期的结果。
  • 谢谢@ozy .. 我做对了。还有一个问题是如何让子进程等待另一个进程(任何)完成,然后弹出一个“按下确定按钮”消息对话框?
  • 你跳到另一个主题,多处理? :) 请把它作为一个新问题详细地提出来,我会在今天回答它。
【解决方案2】:

我猜对了。感谢@ozy

import threading
import wx
from threading import Thread

ID_RUN = 101
ID_RUN2 = 102


class ChildThread(Thread):
    def __init__(self, myframe):
    """Init Worker Thread Class."""
        Thread.__init__(self)
        self.myframe = myframe

    def run(self):
        wx.CallAfter(self.myframe.AfterRun, 'Ok button pressed')


class MyFrame(wx.Frame):
    def __init__(self, parent, ID, title):
        wx.Frame.__init__(self, parent, ID, title)
        panel = wx.Panel(self, -1)
        mainSizer = wx.BoxSizer(wx.HORIZONTAL)
        mainSizer.Add(wx.Button(panel, ID_RUN, "OK"))
        mainSizer.Add(wx.Button(panel, ID_RUN2, "Cancel"))
        panel.SetSizer(mainSizer)
        mainSizer.Fit(self)
        wx.EVT_BUTTON(self, ID_RUN, self.onRun)
        wx.EVT_BUTTON(self, ID_RUN2, self.onRun2)

    def onRun(self, event):
        self.child = ChildThread(myframe=self)
        self.child.daemon = True
        self.child.start()

    def onRun2(self, event):
        self.child2 = threading.Thread(None, self.__run)
        self.child2.daemon = True
        self.child2.start()

    def __run(self):
        wx.CallAfter(self.AfterRun, "Cancel button pressed")

    def AfterRun(self, msg):
        dlg = wx.MessageDialog(self, msg, "Message", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()


class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, "My GUI")
        frame.Show(True)
        frame.Centre()
        return True

app = MyApp(0)
app.MainLoop()

【讨论】:

  • 如何让 ChildThread 等待进程(任何)完成,然后继续显示对话框?