wxPython wx.CallAfter - 如何让它立即执行?

2 投票
2 回答
6806 浏览
提问于 2025-04-18 12:22

当我用 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(),但这样只会让应用程序卡住,停止响应。

2 个回答

-2

你试过用谷歌搜索吗?我试过,找到了几个不错的想法。可以看看下面这个讨论:

你可以试试wx.WakeUpIdle()或者wx.GetApp().ProcessIdle()。我还注意到在文档里,有一个ProcessPendingEvents的方法可以用在wx.App上,所以你也可以试试wx.Getapp().ProcessPendingEvents()

4

正如你所猜的,wx.CallAfter 会把调用的信息放到一个队列里(这个队列叫做待处理事件队列,下一次清空这个队列时会在图形界面线程中处理),然后立刻返回。换句话说,它的设计就是一种“发出请求就不管了”的函数调用方式。

如果你需要获取这个被调用函数的结果,有几种方法可以实现。其中一种是延迟结果模式,基本上就是你会得到一个结果对象,这个对象会在函数调用后接收结果,而调用的代码可以在结果到达时收到通知。在 wx.lib.delayedresult 中有这个模式的实现,可能在其他地方也能找到类似的实现。这个方法的好处是,调用的线程不需要停下来等结果,可以继续处理其他事情。

我认为另一个相当不错的方法是 wxAnyThread,你可以在 https://pypi.python.org/pypi/wxAnyThread/ 找到它。这个模块提供了一个装饰器,可以让方法像普通函数调用一样从任何线程调用,但如果不是从图形界面线程调用,它会使用类似 wx.CallAfter 的处理方式,在UI线程中调用这个函数,然后等待结果,并在结果到达时返回给调用者。所以,虽然在处理UI事件和调用函数时,调用的线程会被阻塞,但使用起来更简单,减少了调用方的复杂性。

撰写回答