菜单栏应用程序永远不会重新激活

时间:2013-02-28 03:45:00

标签: objective-c macos menubar appkit

我正在构建一个Mac应用程序,它只位于菜单栏中,没有停靠项,没有关键窗口,也没有主菜单(info.plist中的LSUIElement设置为YES)。当我第一次启动应用程序时,applicationDidBecomeActive:被调用,正如我所料。但是,一旦另一个应用程序获得焦点,applicationDidBecomeActive:永远不会再被调用。

这可以防止我的应用程序中的文本字段成为第一个响应者。首次打开应用时,文本字段可编辑:

before another app gains focus

但是在另一个应用程序到达前台后,文本字段不可编辑:

after another app gains focus

我尝试了什么:

打开菜单后,menuWillOpen:代表会调用NSMenu。我试过放下以下内容但没有成功:

[NSApp unhide];
[NSApp arrangeInFront:self];
[NSApp activateIgnoringOtherApps:YES];
[NSApp requestUserAttention:NSCriticalRequest];
[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
[[NSRunningApplication currentApplication] unhide];

我认为问题可能与没有任何窗户带到前面有关。我觉得我在这里抓稻草。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

我认为问题在于当NSMenu打开时runloop如何运作,因此您应该在显示菜单之前尝试激活应用程序。如果你有NSStatusItem显示它,我建议你自己这样做:

- (void)toggleMenu:(id)sender
{
  // App might already be active
  if ([NSApp isActive]) {
    [self.statusItem popUpStatusItemMenu:self.menu];
  } else {
    [NSApp activateIgnoringOtherApps:YES];
  }
}

- (void)applicationDidBecomeActive:(NSNotification *)notification
{
  [self.statusItem popUpStatusItemMenu:self.menu];
}

这应该有效,但我认为虽然一般情况下你会有更好的运气而不是菜单。

答案 1 :(得分:1)

您可能需要允许输入-becomeFirstResponder,或者通过覆盖-canBecomeFirstResponder或自行调用“成为”方法。

您可能必须为任何容纳文本输入的视图实现/调用这些方法,或者可能告诉输入视图成为第一个响应者。

无论哪种方式,它都像回应链问题一样。

答案 2 :(得分:1)

尝试在窗口上调用-makeFirstResponder:。 NSWindow通常是NSResponder链的起点。

- (void)menuWillOpen:(NSMenu *)menu {
    [[NSApp mainWindow] makeFirstResponder:yourTextInputField];
}

我假设您的文字字段已经接受了第一响应者,因为您说您的应用最初是以第一响应者的身份启动的。如果没有,请确保您的文本字段覆盖-acceptsFirstResponder:以返回YES

- (BOOL)acceptsFirstResponder {
    return YES;
}

编辑:啊,看到你没有关键窗口。看起来NSMenu实际上有一个与之关联的窗口,调用-makeFirstResponder:是安全的。有些讨论here建议在您的视图中覆盖-viewDidMoveToWindow:,其中包含NSMenu中的文本字段,如下所示:

- (void)viewDidMoveToWindow {
    [super viewDidMoveToWindow];

    [[self window] makeFirstResponder:yourTextInputField];
}