【问题标题】:How to display application icon in menubar even application is quit即使应用程序退出,如何在菜单栏中显示应用程序图标
【发布时间】:2014-07-28 03:23:48
【问题描述】:

我的应用程序在菜单栏中显示一个图标,但是当应用程序退出时,该图标从菜单栏中消失。

我们有没有办法编写代码,使应用程序即使退出也总是在菜单栏中显示。

谢谢。

【问题讨论】:

  • 我已经实现了一个菜单栏图标,但是一旦我退出我的应用程序,它就会从菜单栏中消失。即使我退出了,我也想知道如何始终启用它。
  • 你不能这样做,它没有多大意义。如果应用程序退出,图标会做什么?如果用户退出您的菜单栏应用程序,他们希望这会使图标消失。这就是他们放弃它的原因。如果图标不应该消失,请不要退出应用程序(但如果您阻止用户这样做,则希望他们会生气)。
  • 谢谢肯。但是我想制作这样的防病毒图标,即使应用程序不存在于 Dock 中,它也始终保留在菜单栏中。
  • 如果您不希望应用程序的图标出现在 Dock 中,您通常会将其设为 UI 元素(在其 Info.plist 文件中设置 LSUIElement)。如果您希望它有时有一个 Dock 图标,有时没有,我建议您将其拆分为独立的、互操作的部分:一个位于菜单栏中的 UI 元素和一个显示在 Dock 中的单独的普通应用程序。在 OS X 10.9 及更高版本中,您可以使用 -[NSApplication setActivationPolicy:] 在 UI 元素和常规应用程序之间来回切换。 (方法文档说你不能,但发行说明记录了新功能。)

标签: objective-c macos cocoa


【解决方案1】:

您绝对可以将应用切换到后台(附件)模式,然后再切换回来。从语义上讲,应用程序永远不会退出。

基本思想是使用NSApplicationDelegate 协议在附件和常规应用模式之间来回切换。已经有一些方法可以取消退出、捕获所有正在关闭的窗口以及处理尝试启动您的应用程序的用户,即使它仍在运行。所以把它们放在一起,你会得到下面的代码。

我在这里留下的代码展示了如何加载和卸载由 NSWindowController self.wincon 控制的主 GUI,其中 self 是应用程序委托对象。它加载和控制一个单独的MainWindow.xib。如果您没有主菜单以外的窗口,则可能没有必要。

我还需要设置一个用户首选项以启用所有这些行为。默认情况下,它会真的,真的退出。

我在MainMenu.xib 中什么都没有,但是菜单——切换到附件模式将意味着菜单不显示。

// Helper to close main window and switch to accessory mode
- (void) switchToBackgroundMode
{
    @autoreleasepool {
        // Need to check loaded to prevent closing a closed window and
        //  triggering a second call to applicationShouldTerminateAfterLastWindowClosed
        if ([self.wincon isWindowLoaded]) [self.wincon close];
        self.wincon = nil;
    }

    // Hide the menu and dock icon
    [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
}

#pragma mark Application Delegate Methods

// Called with a CMD-Q
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
    // Cancel terminate if pref set
    if ([MyPreferencesController runInBackground])
    {
        [self switchToBackgroundMode];
        return NSTerminateCancel;
    } 
    return NSTerminateNow;
}

// Called when all windows closed
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
    if ([MYPreferencesController runInBackground]) {
        // This check is necessary to avoid calling switchToBGmode twice on a quit
        if (![NSApp activationPolicy] == NSApplicationActivationPolicyAccessory)
            [self switchToBackgroundMode];
        return NO;
    } else {
        return YES;
    }
}

// Called if the app is in accessory mode and the user activates it through the dock or by
//   clicking a userNotification or trying to open the app
- (BOOL) applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
{
    if (!self.wincon) {
        self.wincon = [[MYMainWindowController alloc] initWithWindowNibName:@"MainWindow"];
    }

    // This ensures that the dock icon comes back
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

    // Show the window
    [self.wincon showWindow:NSApp];
    [self.wincon.window makeKeyAndOrderFront:NSApp];
    return YES;
}

注释已于 2016 年 6 月 10 日添加,因为这已经引起了一些关注:

有一个older answer to this question。它对更改历史进行了很好的讨论,但缺少示例代码。

最后,这个答案和问题完全缺少LSUIElement 关键字,这是针对此类应用程序的历史 OSX plist 设置。如上述答案和this more recent question 所述,LSUIElement 应被视为已弃用。如果您发现有一篇旧博客文章提到了它,希望您能找到更多建议不要使用它的最新代码示例。

【讨论】:

  • 谢谢史蒂夫。该代码有助于实现所需的功能。
  • 简直就是 B R I L L I A N T!谢谢。
猜你喜欢
  • 2011-07-27
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-30
相关资源
最近更新 更多