【问题标题】:Menu Bar App Never Becomes Reactivated菜单栏应用程序永远不会重新激活
【发布时间】:2013-02-28 03:44:59
【问题描述】:

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

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

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

我尝试过的:

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

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

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

【问题讨论】:

  • 如果应用程序从未重新启动,为什么还要再次调用它。如果它在菜单栏中,它的进程不是作为一种准守护进程存在吗?
  • 也许它没有任何关系,但我最近遇到了一个问题,iOS 没有在恢复事件之后将视图作为第一响应者(当它是恢复之前的第一响应者时)。解决方法是在发送 becomeFirstResponder 消息之前 resignFirstResponder。不知道为什么,但它得到了 iOS 的支持。也许这里有类似的东西在起作用?
  • 嘿,Ash,问题可能与 NSMenu 有关。将它用于文本输入从来都不是一个好主意。您是否尝试过使用 NSWindow 的相同步骤?

标签: objective-c macos menubar appkit


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      尝试在您的窗口上调用-makeFirstResponder:。 NSWindow 通常是 NSResponder 链的开始。

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

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

      - (BOOL)acceptsFirstResponder {
          return YES;
      }
      

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

      - (void)viewDidMoveToWindow {
          [super viewDidMoveToWindow];
      
          [[self window] makeFirstResponder:yourTextInputField];
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-17
        • 2017-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-24
        • 2018-07-01
        相关资源
        最近更新 更多