8

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

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

在另一个应用程序获得焦点之前

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

在另一个应用程序获得焦点之后

我试过的:

打开菜单时,在的委托menuWillOpen:上调用。NSMenu我尝试放置以下内容但没有成功:

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

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

4

3 回答 3

3

我认为问题在于运行循环在 aNSMenu打开时如何运行,因此您应该在显示菜单之前尝试激活应用程序。如果您要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];
}

这应该可行,但我认为总的来说,使用实际窗口而不是菜单会更好。

于 2013-02-28T16:37:05.320 回答
1

试着-makeFirstResponder:在你的窗户上打电话。NSWindow 通常是 NSResponder 链的开始。

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

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

- (BOOL)acceptsFirstResponder {
    return YES;
}

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

- (void)viewDidMoveToWindow {
    [super viewDidMoveToWindow];

    [[self window] makeFirstResponder:yourTextInputField];
}
于 2013-02-28T09:19:24.380 回答
1

您可能需要允许您的输入-becomeFirstResponder,可能是通过覆盖-canBecomeFirstResponder或自己调用 become 方法。

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

无论哪种方式,它都像是一个响应链问题。

于 2013-02-28T03:51:46.133 回答