macos - 实现自定义 Cocoa 事件跟踪循环

标签 macos cocoa

我正在开发一个自定义跨平台 UI 库,该库需要一个显示弹出窗口的同步“ShowPopup”方法,运行一个事件循环直到它完成,并在单击弹出窗口外部或按 Escape 时自动取消。键盘、鼠标和滚轮事件需要分派(dispatch)到弹出窗口,但其他事件(绘画、绘图、计时器等)需要在循环运行时分派(dispatch)到它们的常规目标。

编辑:为澄清起见,弹出窗口是指这种菜单样式的弹出窗口,而不是警报/对话框等...

Cantabile Popup

在 Windows 上,我通过调用 GetMessage/DispatchMessage 并根据需要过滤和分派(dispatch)消息来实现这一点。工作正常。

但是,我对 Cocoa/OS X 的经验要少得多,并且发现整个事件循环/调度范例有点令人困惑。我看过以下文章,它解释了如何实现与我需要的非常相似的鼠标跟踪循环:

http://stpeterandpaul.ca/tiger/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/chapter_5_section_4.html

但是... 关于这件事,我有些担心。

  • 链接文章指出:“应用程序的主线程在事件跟踪循环期间无法处理任何其他请求,并且计时器可能不会触发”。可能不?为什么不,当不时,如何确保他们这样做?
  • nextEventMatchingMask:untilDate:inMode:dequeue: 的文档状态“与指定事件类型之一不匹配的事件留在队列中。”。这似乎有点奇怪。这是否意味着如果事件循环只要求鼠标事件,那么一旦循环完成,任何按下的键都会被处理?那会很奇怪。
  • 是否可以在不删除事件队列中查看消息。例如:我的库的 Windows 版本在外部单击时使用它来关闭弹出窗口,但将单击事件留在队列中,以便在另一个按钮上单击弹出窗口外部不需要第二次单击。
  • 我已经阅读并重新阅读了有关运行循环模式的内容,但仍然没有真正理解。一个很好的解释这些是为了什么会很棒。
  • 是否有任何其他为弹出窗口实现事件循环的好例子。更好的是内置 NSApplication 运行循环的伪代码。

  • 另一种表述方式... Cocoa 相当于 Windows 的 PeekMessage(..., PM_REMOVE) , PeekMessage(..., PM_NOREMOVE)DispatchMessage() .

    非常感谢任何帮助。

    最佳答案

    当您使用该术语时,“弹出窗口”到底是什么?该术语在不同的 GUI API 中意味着不同的东西。它只是一个模态对话框窗口吗?

    问题编辑更新:

    看来您只想实现自定义菜单。苹果提供了一个示例项目,CustomMenus ,这说明了该技术。它是 WWDC 2010 session 视频之一的伴侣,Session 145, "Key Event Handling in Cocoa Applications" .

    根据您需要达到的具体目标,您可能希望使用 NSAlert .或者,您可以使用自定义窗口并使用 -runModalForWindow: 以模态方式运行它。 NSApplication的方法.

    为了满足用户在窗口外单击时结束模态 session 的要求,您可以使用本地事件监视器。在(现代的,当前的)Cocoa 事件处理指南中甚至有一个这样的功能示例:Monitoring Events .

    综上所述,以下是(希望不再相关)您的具体问题的答案:

    1. The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and timers might not fire". Might not? Why not, when not, how to make sure they do?


    因为计时器是在特定的运行循环模式或一组模式中安排的。请参阅下面问题 4 的答案。在运行事件跟踪循环时,您通常会使用事件跟踪模式,因此未在该模式下安排的计时器将不会运行。

    您可以为事件跟踪循环使用默认模式,但这确实不是一个好主意。它可能会导致意外的重新进入。

    假设您的弹出窗口类似于模式窗口,您可能应该使用 NSModalPanelRunLoopMode .

    1. The docs for nextEventMatchingMask:untilDate:inMode:dequeue: states "events that do not match one of the specified event types are left in the queue.". That seems a little odd. Does this mean that if an event loop only asks for mouse events then any pressed keys will be processed once the loop finishes? That'd be weird.


    是的,就是这个意思。防止这种奇怪的结果由你决定。如果您要阅读这十年的 Cocoa 事件处理指南版本,您会发现 a section on how to deal with this . ;-P

    1. Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close the popup when it's clicked outside, but leaves the click event in the queue so that clicking outside the popup on a another button doesn't require a second click.


    是的。你注意到nextEventMatchingMask:untilDate:inMode:dequeue: 的“dequeue:”参数了吗? ?如果您通过 NO为此,事件将留在队列中。

    1. I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.


    如果不知道您对什么感到困惑以及 Apple guide 的作用如何,就很难知道该告诉您什么让你失望了。

    您是否熟悉使用围绕 select() 的循环处理多个异步通信 channel ? , poll() , epoll() , 或 kevent() ?有点像那样,但更加自动化。您不仅构建了一个数据结构,其中列出了您想要监视的输入源以及您感兴趣的输入源上的特定事件,而且每个输入源还具有与之关联的回调。运行 run loop 就像调用上述函数之一来等待输入,而且当输入到达时,调用与源关联的回调来处理该输入。您可以运行该循环的单圈,运行它直到特定时间,甚至无限期地运行它。

    使用运行循环,可以将输入源组织成集合。这些集合称为“模式”并由名称(即字符串)标识。当你运行一个运行循环时,你可以通过指定它应该在哪种模式下运行来指定它应该监控的一组输入源。其他输入源仍然是运行循环知道的,但只是暂时忽略。
    -nextEventMatchingMask:untilDate:inMode:dequeue:方法或多或少是在内部运行线程的运行循环。除了运行循环中已经存在的任何输入源之外,它还临时添加一个输入源来监视来自窗口系统的事件,包括鼠标和按键事件。

    1. Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in NSApplication run loop does.


    有旧的 Apple 示例代码,这实际上是他们对 GLUT 的实现。它提供a subclass of NSApplication 并覆盖 -run方法。当你去掉一些只与应用程序启动或 GLUT 相关的东西时,它非常简单。这只是一个循环 -nextEventMatchingMask:...-sendEvent: .

    关于macos - 实现自定义 Cocoa 事件跟踪循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43991976/

    相关文章:

    cocoa - 从 cocoa 应用程序访问网络服务器

    xcode - NSTextView/NSScrollView - 有几个问题可以帮助我理解它的正确用法

    macos - 是否可以通过我的应用程序分发图像单元?

    cocoa - 使用多个 WebView 进行打印

    python - 在 OSX 上为 virtualenv 设置 Python 32 位和 64 位模式

    macos - 音频输入 SNR 处理

    java - 获取 Mac 中运行的驱动程序

    objective-c - 如何在 CIImage 上画线/弧?

    ruby - 在 Mac OS Mavericks (10.9.2) 上安装 Jekyll 时出错

    macos - 核心数据云同步 - 需要逻辑方面的帮助