【问题标题】:wxPython wx.CallAfter - how do I get it to execute immediately?wxPython wx.CallAfter - 我如何让它立即执行?
【发布时间】:2014-07-07 16:07:09
【问题描述】:

当我使用 wx.CallAfter 执行函数时,会在其中设置一个变量。我希望能够在下一行获得该变量的值,但是 CallAfter 似乎稍后会执行很多函数。我认为它会将其推送到稍后处理的某个队列中或其他什么...有没有办法让该队列立即得到处理?

这是wx.CallAfter的代码:

def CallAfter(callableObj, *args, **kw):
    """
    Call the specified function after the current and pending event
    handlers have been completed.  This is also good for making GUI
    method calls from non-GUI threads.  Any extra positional or
    keyword args are passed on to the callable when it is called.

    :see: `wx.CallLater`
    """
    assert callable(callableObj), "callableObj is not callable"
    app = wx.GetApp()
    assert app is not None, 'No wx.App created yet'

    if not hasattr(app, "_CallAfterId"):
        app._CallAfterId = wx.NewEventType()
        app.Connect(-1, -1, app._CallAfterId,
                    lambda event: event.callable(*event.args, **event.kw) )
    evt = wx.PyEvent()
    evt.SetEventType(app._CallAfterId)
    evt.callable = callableObj
    evt.args = args
    evt.kw = kw
    wx.PostEvent(app, evt)

我的假设是 wx.PostEvent 将“evt”放在“app”的某个内部容器中,并且在某个时候该容器被迭代并且所有元素都执行了它们的“可调用”或什么?所以基本上我需要立即导致这种情况发生,但我找不到任何看起来像“wx.ForceEventProcessing()”或“wx.FlushEventsQueue”的东西

我尝试在定义方法的面板中调用 self.Update(),但这只是阻止了应用程序并停止响应。

【问题讨论】:

  • 在我看来,如果你对线程感到满意,wx.CallAfter 永远不需要。
  • @user2963623 关于在我传递给 wx.CallAfter 的函数中调用 wx 后可能导致应用程序完全挂起的任何想法?它不会引发异常,也不会输出任何警告,并且在它之后也不会遇到断点。它只是挂断了应用程序。
  • 这是指您之前使用msvcrt.getch()注册按键的问题吗?
  • msvcrt.getch() 似乎没有与 PyDev 一起工作:bugs.eclipse.org/bugs/show_bug.cgi?id=375172,但是我目前正在做的事情过去常常工作(在移动到另一个线程并使用 wx.CallAfter() 之前)。但是是的,它以与msvcrt.getch() 相同的方式挂断,并且在控制台或异常中没有留下警告或错误消息。
  • hmm 我注意到在我停止调试后,PyDev 告诉我调用wx.CallAfter() 的线程的退出代码是-1

标签: python events wxpython


【解决方案1】:

正如您所猜到的,wx.CallAfter 将调用信息添加到队列(待处理的事件队列,下次清空事件队列时在 GUI 线程中处理),然后立即返回。换句话说,它旨在成为一个“即发即弃”的函数调用。

如果您需要获取该调用函数的结果,可以采取一些方法。一种是延迟结果模式,基本上你会得到一个结果对象,它会在函数调用被调用后接收到它的结果,并且调用代码可以在发生这种情况时得到通知。在wx.lib.delayedresult 中有一个实现,并且可能在不同的地方可以找到这种模式的其他实现。这种方法的好处是调用线程不必停止并等待结果,如果需要,可以继续处理其他事情。

我认为另一种非常好的方法是wxAnyThread,可以在https://pypi.python.org/pypi/wxAnyThread/ 找到。这个模块提供了一个装饰器,它允许从任何线程调用方法,就像正常的函数调用一样,但是当从 GUI 线程以外的其他东西调用时,它将使用wx.CallAfter-like 处理在 UI 线程中调用函数,并且然后等待结果,并在收到结果时将其返回给调用者。因此,虽然在处理 UI 事件和调用函数时调用线程被阻塞,但使用起来要简单得多,并且降低了调用方的复杂度。

【讨论】:

  • 我尝试了 wxAnyThread,我用@anythread 装饰了我的方法,然后创建了一个线程:worker_thread = Thread(target = self.WxCallsMethod, name = "Worker Thread") worker_thread.start() 发生的情况是,WxCallsMethod 永远不会被调用,它开头的断点没有被命中。如果我删除@anythread,它会遇到断点,但是当它执行 wx 调用时它当然会崩溃。我尝试将@anythread 方法放在非@anythread 方法中,当我使用非anythread 启动线程时,它会遇到断点,但再次在@anythread 处失败......
  • 您需要提供一个小的、可运行的代码示例。
  • @Bogomil 你绝对不应该在线程的目标函数上使用@anythread,但是你可以在它调用的任何需要与GUI交互的函数上使用它。
【解决方案2】:

您尝试过 Google 吗?我做到了,我有几个想法。请参阅以下主题:

试试 wx.WakeUpIdle()wx.GetApp().ProcessIdle()。我还在docs 中注意到 wx.App 有一个 ProcessPendingEvents 方法,因此您也可以尝试 wx.Getapp().ProcessPendingEvents()

【讨论】:

  • hmm,现在在调用 wx.GetApp().ProcessPendingEvents() 任何执行 wx-call 并且我传递给 wx.CallAfter 的函数之后,会导致线程终止而不会留下任何错误消息或引发任何异常。跨度>
  • 可能是因为您从错误的线程调用ProcessPendingEvents。这与从错误的线程调用你的函数有同样的问题(甚至更多)。
  • wx.PostEvent 已经调用了WakeUpIdle。它基本上只是将原生 NULL 事件添加到事件队列中,因此如果它已经为空,它一定会及时再次“变空”。
  • @RobinDunn - 我不知道。真是太好了!
  • 在 wx.CallAfter 之后调用 wx.GetApp().ProcessPendingEvents() 为我解决了类似的问题
猜你喜欢
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-04
  • 2012-12-05
  • 1970-01-01
相关资源
最近更新 更多