popUpMenuPositioningItem:atLocation:inView:切换到另一个应用程序时挂起

时间:2011-04-02 04:43:15

标签: objective-c macos cocoa menu

我正在开发无泊坞应用程序(LSUIElement true)。当用户点击相应的NSStatusItem或使用键盘快捷键时,应用程序会弹出一个菜单。

我的问题是,只要用户切换到另一个应用程序(使用⌘-TAB)而不首先解除菜单,所有以编程方式弹出菜单的方法都会挂起。我在popUpMenuPositioningItem:atLocation:inView:popUpContextMenu:withEvent:forView:)上尝试了NSStatusItempopUpStatusItemMenu:和相应的方法。

如果用户使用ESC键取消菜单一切正常,但如果用户切换到其他应用程序,则上述方法永远不会返回(它们似乎同步运行并在菜单解除时返回)。该应用程序不会崩溃,并且有一些技巧可以重新获得控制权(调用exposé,或点击弹出菜单的任何NSStatusItem)。

如果应用程序有停靠图标(即将LSUIElement设置为false),问题就会消失。

这是使用键盘快捷键时弹出菜单的代码:

[mainMenu popUpMenuPositioningItem:[mainMenu itemAtIndex:0]
                        atLocation:[NSEvent mouseLocation]
                            inView:nil];

这是点击NSStatusItem时弹出菜单的代码:

- (void)mouseDown:(NSEvent *)event
{
    [statusItem popUpStatusItemMenu:[statusItem menu]];
}

mouseDown:方法位于NSView附加的自定义NSStatusItem中。

有关如何解决这个问题的想法吗?

感谢您的帮助。

更新

问题还与正在激活的应用程序有关(我在显示菜单之前使用[NSApp activateIgnoringOtherApps:YES];,或者在某些情况下无法使用键盘导航菜单。)

1 个答案:

答案 0 :(得分:4)

问题似乎是由于应用程序激活和popUpMenu在同一个事件周期中发生。我找到了一种解决方法,详见this post

总结一下,您需要先激活应用程序(使用[NSApp activateIgnoringOtherApps:YES];),然后弹出菜单,确保在新的事件周期中发生这种情况:您可以使用NSTimer来触发菜单

- (void) someMethod {
    // Some code
    [NSApp activateIgnoringOtherApps:YES];
    [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(showMenu) userInfo:nil repeats:NO];
    //Some other code
}

- (void) showMenu {
    // This will show the menu at the current mouse position
    [aMenu popUpMenuPositioningItem:[mainMenu itemAtIndex:0] atLocation:[NSEvent mouseLocation] inView:nil];
}
相关问题