wxPython:线程 GUI -->使用自定义事件处理程序

发布于 2024-08-23 07:23:39 字数 1272 浏览 7 评论 0原文

我正在尝试学习如何在主 GUI 应用程序上运行线程来执行串行端口发送/接收,同时保持 GUI 处于活动状态。我最好的谷歌搜索尝试让我找到了 wxpython wiki: http://wiki.wxpython.org/LongRunningTasks 其中提供了几个示例。我决定学习第一个示例,涉及在选择特定按钮时启动工作线程。

我无法理解自定义事件定义:

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data

主要是

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

我认为 EVT_RESULT 被放置在类之外,以便使其可以被两个类调用(使其成为全局的?)

并且..主 GUI 应用程序监视线程的进度via:

# Set up event handler for any worker thread results
EVT_RESULT(self,self.OnResult)

我还注意到,在很多例子中,当作者使用时,

from wx import *

他们只是将事物绑定在一起

EVT_SOME_NEW_EVENT(self, self.handler)

,而不是

wx.Bind(EVT_SOME_NEW_EVENT, self.handler)

“这并不能帮助我更快地理解它”。 谢谢,

I am trying to learn how to run a thread off the main GUI app to do my serial port sending/receiving while keeping my GUI alive. My best Googling attempts have landed me at the wxpython wiki on: http://wiki.wxpython.org/LongRunningTasks which provides several examples. I have settled on learning the first example, involving starting a worker thread when the particular button is selected.

I am having trouble understanding the custom-event-definition:

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data

Primarily the

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

I think EVT_RESULT is placed outside the classes so as to make it call-able by both classes (making it global?)

And.. the main GUI app monitors the thread's progress via:

# Set up event handler for any worker thread results
EVT_RESULT(self,self.OnResult)

I also notice that in a lot of examples, when the writer uses

from wx import *

they simply bind things by

EVT_SOME_NEW_EVENT(self, self.handler)

as opposed to

wx.Bind(EVT_SOME_NEW_EVENT, self.handler)

Which doesn't help me understand it any faster.
Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

银河中√捞星星 2024-08-30 07:23:39

这是定义自定义事件的旧风格。有关详细信息,请参阅迁移指南

摘自迁移指南:

如果您创建自己的自定义事件
类型和 EVT_* 函数,而你
希望能够将它们与
绑定上面的方法然后你应该
将您的 EVT_* 更改为 wx.PyEventBinder 的实例,而不是
功能。例如,如果您曾经
有这样的东西:

myCustomEventType = wxNewEventType()
def EVT_MY_CUSTOM_EVENT(win, id, func):
    win.Connect(id, -1, myCustomEventType, func)

像这样改变它:

myCustomEventType = wx.NewEventType()
EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1)

这是另一篇文章 我用几个示例程序制作的这些程序正是您所寻找的。

That's the old style of defining custom events. See the migration guide for more information.

Taken from the migration guide:

If you create your own custom event
types and EVT_* functions, and you
want to be able to use them with the
Bind method above then you should
change your EVT_* to be an instance of wx.PyEventBinder instead of a
function. For example, if you used to
have something like this:

myCustomEventType = wxNewEventType()
def EVT_MY_CUSTOM_EVENT(win, id, func):
    win.Connect(id, -1, myCustomEventType, func)

Change it like so:

myCustomEventType = wx.NewEventType()
EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1)

Here is another post that I made with a couple of example programs that do exactly what you are looking for.

美羊羊 2024-08-30 07:23:39

你可以这样定义事件:

from wx.lib.newevent import NewEvent

ResultEvent, EVT_RESULT = NewEvent()

你可以这样发布事件:

wx.PostEvent(handler, ResultEvent(data=data))

像这样绑定它:

def OnResult(event):
    event.data

handler.Bind(EVT_RESULT, OnResult)

但是如果你只需要从主线程中的非主线程进行调用,你可以使用 wx.CallAfter这里是一个示例。

当您不想对谁负责什么进行硬编码时,自定义事件非常有用(请参阅观察者设计模式)。例如,假设您有一个主窗口和几个子窗口。假设当主窗口发生某种变化时,需要刷新某些子窗口。在这种情况下,主窗口可以直接刷新这些子窗口,但更优雅的方法是定义一个自定义事件并让主窗口将其发布到自身(而不打扰谁需要对其做出反应)。然后,需要对该事件做出反应的子级可以通过绑定到该事件来自行完成(如果有多个事件,那么他们调用 event.Skip() 非常重要,以便所有绑定方法被调用)。

You can define events like this:

from wx.lib.newevent import NewEvent

ResultEvent, EVT_RESULT = NewEvent()

You post the event like this:

wx.PostEvent(handler, ResultEvent(data=data))

Bind it like this:

def OnResult(event):
    event.data

handler.Bind(EVT_RESULT, OnResult)

But if you just need to make a call from a non-main thread in the main thread you can use wx.CallAfter, here is an example.

Custom events are useful when you don't want to hard code who is responsible for what (see the observer design pattern). For example, lets say you have a main window and a couple of child windows. Suppose that some of the child windows need to be refreshed when a certain change occurs in the main window. The main window could directly refresh those child windows in such a case but a more elegant approach would be to define a custom event and have the main window post it to itself (and not bother who needs to react to it). Then the children that need to react to that event can do it them selves by binding to it (and if there is more than one it is important that they call event.Skip() so that all of the bound methods get called).

疾风者 2024-08-30 07:23:39

您可能想要使用 Python 线程和队列,而不是自定义事件。我有一个 wxPython 程序(OpenSTV),它加载大文件,导致 gui 在加载过程中冻结。为了防止冻结,我调度一个线程来加载文件并使用队列在 GUI 和线程之间进行通信(例如,向 GUI 传达异常)。

  def loadBallots(self):
    self.dirtyBallots = Ballots()
    self.dirtyBallots.exceptionQueue = Queue(1)
    loadThread = Thread(target=self.dirtyBallots.loadUnknown, args=(self.filename,))
    loadThread.start()

    # Display a progress dialog
    dlg = wx.ProgressDialog(\
      "Loading ballots",
      "Loading ballots from %s\nNumber of ballots: %d" % 
      (os.path.basename(self.filename), self.dirtyBallots.numBallots),
      parent=self.frame, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME
    )
    while loadThread.isAlive():
      sleep(0.1)
      dlg.Pulse("Loading ballots from %s\nNumber of ballots: %d" %
                (os.path.basename(self.filename), self.dirtyBallots.numBallots))
    dlg.Destroy()

if not self.dirtyBallots.exceptionQueue.empty():
  raise RuntimeError(self.dirtyBallots.exceptionQueue.get())

You may want to use Python threads and queues and not custom events. I have a wxPython program (OpenSTV) that loads large files that caused the gui to freeze during the loading. To prevent the freezing, I dispatch a thread to load the file and use a queue to communicate between the gui and the thread (e.g., to communicate an exception to the GUI).

  def loadBallots(self):
    self.dirtyBallots = Ballots()
    self.dirtyBallots.exceptionQueue = Queue(1)
    loadThread = Thread(target=self.dirtyBallots.loadUnknown, args=(self.filename,))
    loadThread.start()

    # Display a progress dialog
    dlg = wx.ProgressDialog(\
      "Loading ballots",
      "Loading ballots from %s\nNumber of ballots: %d" % 
      (os.path.basename(self.filename), self.dirtyBallots.numBallots),
      parent=self.frame, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME
    )
    while loadThread.isAlive():
      sleep(0.1)
      dlg.Pulse("Loading ballots from %s\nNumber of ballots: %d" %
                (os.path.basename(self.filename), self.dirtyBallots.numBallots))
    dlg.Destroy()

if not self.dirtyBallots.exceptionQueue.empty():
  raise RuntimeError(self.dirtyBallots.exceptionQueue.get())
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文