我正在开发一个自定义跨平台UI库,它需要一个显示弹出窗口的同步“ShowPopup”方法,运行一个事件循环直到它完成,并在弹出窗口外部或按下escape时自动取消。需要将键盘,鼠标和滚轮事件分派到弹出窗口,但是在循环运行时需要将其他事件(绘画,绘图,计时器等)分派到常规目标。
编辑:为了澄清,通过弹出窗口,我的意思是这种菜单式弹出窗口,而不是警报/对话框等......
在Windows上,我通过调用GetMessage / DispatchMessage并根据需要过滤和分派消息,相当简单地实现了这一点。工作正常。
我对Cocoa / OS X的经验却少得多,但发现整个事件循环/调度范例有点令人困惑。我已经看过以下文章,它解释了如何实现与我需要的非常类似的鼠标跟踪循环:
但是...有一些与我有关的事情。
链接文章指出:“应用程序的主线程无法在事件跟踪循环期间处理任何其他请求,并且计时器可能无法触发”。也许不会?为什么不,如果没有,如何确保他们这样做?
nextEventMatchingMask:untilDate:inMode:dequeue:状态的文档“与指定事件类型之一不匹配的事件将保留在队列中。”这看起来有点奇怪。这是否意味着如果事件循环仅询问鼠标事件,那么一旦循环结束,任何按下的键都将被处理?那太奇怪了。
是否可以在不删除事件队列的情况下查看事件队列中的消息。例如:我的库的Windows版本使用此版本在外部单击时关闭弹出窗口,但将click事件留在队列中,以便在另一个按钮的弹出窗口外单击不需要再次单击。
< / LI>我已经阅读并重新阅读了关于运行循环模式但仍然没有真正得到它。对这些内容的一个很好的解释是很好的。
是否有其他为弹出窗口实现事件循环的好例子。更好的是内置NSApplication运行循环的伪代码。
另一种放置所有这些的方法...... Cocoa相当于Windows PeekMessage(..., PM_REMOVE)
,PeekMessage(..., PM_NOREMOVE)
和DispatchMessage()
。
非常感谢任何帮助。
答案 0 :(得分:2)
&#34; popup&#34;究竟是什么?当你使用这个词时?该术语在不同的GUI API中意味着不同的东西。它只是一个模态对话窗口吗?
要对问题进行修改的更新:
您似乎只想实现自定义菜单。 Apple提供了一个示例项目CustomMenus,该项目说明了该技术。它是其中一个WWDC 2010会话视频Session 145, "Key Event Handling in Cocoa Applications"的伴侣。
根据您需要实现的目标,您可能需要使用NSAlert
。或者,您可以使用自定义窗口,然后使用-runModalForWindow:
的{{1}}方法以模态方式运行它。
为了满足用户在窗口外单击时结束模态会话的要求,您可以使用本地事件监视器。在(现代的,当前的)Cocoa事件处理指南Monitoring Events中,甚至还有一个这样的功能的例子。
所有这些都说明了这里(希望不再相关)你的具体问题的答案:
- 链接文章指出:&#34;应用程序的主线程无法在事件跟踪循环期间处理任何其他请求 定时器可能不会开火#34;也许不会?为什么不,如果没有,如何制作 他们确定吗?
醇>
因为计时器是在特定的运行循环模式或一组模式中安排的。请参阅下面问题4的答案。运行事件跟踪循环时,通常会使用事件跟踪模式,因此未在该模式下调度的计时器将无法运行。
您可以使用默认模式进行事件跟踪循环,但这并不是一个好主意。这可能会导致意外的重新入侵。
假设您的弹出窗口类似于模态窗口,您应该使用NSApplication
。
- nextEventMatchingMask:untilDate:inMode:dequeue:的文档 state&#34;与指定事件类型之一不匹配的事件是 留在队列中。&#34;。这看起来有点奇怪。这是否意味着如果 一个事件循环只询问鼠标事件然后按任何键 循环完成后处理?这很奇怪。
醇>
是的,这意味着什么。由您来阻止这种奇怪的结果。如果您在这十年中阅读了“可可事件处理指南”的一个版本,那么您将找到a section on how to deal with this。 ;-P
- 是否可以在不删除事件队列的情况下查看事件队列中的消息。例如:我的库的Windows版本使用它来关闭 弹出窗口在外面点击时,但是将click事件留在了 排队,以便在另一个按钮的弹出窗口外点击不会 需要再次点击。
醇>
是。你注意到了#34; dequeue:&#34;参数NSModalPanelRunLoopMode
?如果您为此传递nextEventMatchingMask:untilDate:inMode:dequeue:
,则事件将保留在队列中。
- 我已经阅读并重新阅读了关于运行循环模式但仍然没有真正得到它。对这些内容的一个很好的解释是很好的。
醇>
如果不知道你对此感到困惑以及Apple guide如何让你失败,很难知道告诉你什么。
您是否熟悉使用NO
,select()
,poll()
或epoll()
的循环处理多个异步通信渠道?它有点像那样,但更加自动化。您不仅要构建一个数据结构,列出您要监视的输入源以及您感兴趣的那些输入源上的特定事件,而且每个输入源还有一个与之关联的回调。运行run循环就像调用上述函数之一来等待输入,但是当输入到达时,调用与源相关的回调来处理该输入。您可以运行该循环的单圈,运行它直到特定时间,或者甚至无限期地运行它。
使用运行循环,输入源可以组织成集。这些集合被称为&#34;模式&#34;并通过名称(即字符串)进行识别。当您运行一个运行循环时,您可以通过指定它应该运行的模式来指定它应该监视哪组输入源。其他输入源仍然是运行循环已知的,但只是暂时被忽略。
kevent()
方法或多或少是在内部运行线程的运行循环。除了运行循环中已存在的任何输入源之外,它还临时添加一个输入源来监视来自窗口系统的事件,包括鼠标和键事件。
- 是否有其他为弹出窗口实现事件循环的好例子。更好的是内置的伪代码 NSApplication run loop确实。
醇>
有旧Apple样本代码,实际上是他们对GLUT的实现。它提供a subclass of NSApplication
并覆盖-nextEventMatchingMask:untilDate:inMode:dequeue:
方法。当你剥离一些仅与应用程序启动或GLUT相关的东西时,它非常简单。它只是-run
和-nextEventMatchingMask:...
的循环。