【问题标题】:`NSStatusItem` created from `main()` doesn't show up on system status bar从 `main()` 创建的 `NSStatusItem` 未显示在系统状态栏上
【发布时间】:2020-04-28 08:06:58
【问题描述】:

我正在尝试使用NSStatusItem 在系统状态栏上创建一个可点击的图标来制作一个简单的 macOS Cocoa 应用程序。但是,当我启动我的应用程序时,我收到了这个警告并且图标没有出现:

2020-03-03 14:43:11.564 Mocha_bug_example[936:39572] CGSGetActiveMenuBarDrawingStyle((CGSConnectionID)[NSApp contextID], &sCachedMenuBarDrawingStyle) returned error 268435459 on line 46 in NSStatusBarMenuBarDrawingStyle _NSStatusBarGetCachedMenuBarDrawingStyle(void)

这是我的应用程序的最小可重现示例:

#import <AppKit/AppKit.h>

NSStatusItem* statusItem;

int main (int argc, char* argv[]) {
        statusItem = [NSStatusBar.systemStatusBar statusItemWithLength: -1];
        statusItem.button.title = @"foobar";
        statusItem.visible = YES;

        [NSApplication.sharedApplication run];
        return 0;
}

我编译并运行了这样的示例:

MacBook-Air-5:Mocha ericreed$ clang -o Mocha_bug_example -framework AppKit -fobjc-arc Mocha_bug_example.m
MacBook-Air-5:Mocha ericreed$ ./Mocha_bug_example
2020-03-03 14:43:11.564 Mocha_bug_example[936:39572] CGSGetActiveMenuBarDrawingStyle((CGSConnectionID)[NSApp contextID], &sCachedMenuBarDrawingStyle) returned error 268435459 on line 46 in NSStatusBarMenuBarDrawingStyle _NSStatusBarGetCachedMenuBarDrawingStyle(void)
[Application hung until I pressed Ctrl+C]
^C
MacBook-Air-5:Mocha ericreed$ 

注意:禁用自动引用计数并在调用run 后添加[statusItem release]; 作为this similar question 建议没有明显区别。

【问题讨论】:

    标签: cocoa nsstatusitem nsapplication nsstatusbar


    【解决方案1】:

    这是如何将状态栏项目添加到命令行应用程序 mac osx cocoa

    改编 apodidae 对 Swift 的回答。只需将其放在 main.swift 文件中即可:

    let app = NSApplication()
    let statusItem = NSStatusBar.system.statusItem(withLength: -1)
    statusItem.button!.title = "PENIS!"
    app.run()
    

    我不了解 NSReleasePool 包含的 Apodidae 的详细信息,但没有它对我有用。

    【讨论】:

    • >我不了解 NSReleasePool 的详细信息 - 在 Swift 中不是问题,因为那里没有使用 NSReleasePool(但在 objc 中使用)。
    • 我想你可能拼错了 PENCIL。
    【解决方案2】:
    #import <Cocoa/Cocoa.h>
    
    int main(){
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
     NSApplication *application = [NSApplication sharedApplication];
     NSStatusItem* statusItem;
     statusItem = [NSStatusBar.systemStatusBar statusItemWithLength: -1];
     statusItem.button.title = @"foobar";
     statusItem.visible = YES;
     [application run];
     [pool drain];
     return 0;
    }
    

    使用名称“statusBar_SO.m”保存文件

    从终端编译: clang statusBar_SO.m -framework Cocoa -o statusBar && ./statusBar

    【讨论】:

    • 这正是我所需要的!请参阅我对 swift 版本的单独答案。
    • 有趣...由于我使用的是自动引用计数,因此在我的情况下不需要NSAutoreleasePool。我的问题可能是使用 AppKit 而不是 Cocoa,不确定。我也会试一试。
    【解决方案3】:

    这不是main()可以做的事情。

    除了极端异常情况,千万不要修改应用模板自带的main(),必须调用NSApplicationMain()

    int main(int argc, char *argv[])
    {
        // start the application
        return NSApplicationMain(argc, (const char **) argv);
    }
    

    在您调用 NSApplicationMain() 之前,Cocoa 框架不会被初始化,并且在此之前通常无法使用。

    此类设置应在applicationWillFinishLaunchingapplicationDidFinishLaunching 中完成。

    更新

    原发帖人使用Xcode,愿意独自闯荡荒野。 ;)

    这也意味着他们的应用程序包将没有通常会创建和连接应用程序委托对象、主菜单等的主 NIB 文件。

    有些勇敢的人勇敢地闯入了这片土地,您可以在Creating a Cocoa application without NIB files 阅读有关它的信息。

    【讨论】:

    • 有道理。所以我应该重组我的应用程序以使用NSApplicationDelegate 之后的对象和这些函数并将其分配给NSApplication.sharedApplication.delegate
    • (一旦我确认这是问题,我会接受你的回答)
    • 是的,这正是您应该做的。如果您使用标准的 Cocoa 应用程序模板之一,那么应该已经创建了该代码(连接到 NSApplication.delegate 属性的应用程序委托对象)。您需要做的就是将方法添加到委托类中。
    • 对不起,我一直很忙。我已经进行了一些重组以使我的应用程序使用NSApplicationMain 启动——我必须添加Info.plistNSPrincipalClass。我还创建了一个委托并使用NSApplication.setDelegate:delegate 将其分配给应用程序。应用程序的图标出现,但委托函数似乎没有被调用。这是我的仓库:github.com/HewwoCraziness/Mocha_bug_example(顺便感谢大家的帮助)
    • 通常你使用主NIB。创建一个 Cocoa 应用程序是“困难的方式”……嗯……很难。有很多细节,但是创建和连接委托对象的子类NSApplication 将是一种解决方案。查看Creating a Cocoa application without NIB files。不推荐,但祝你好运
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-21
    相关资源
    最近更新 更多