在我的应用程序主菜单中设置项目标题?

发布于 2024-10-17 07:11:09 字数 555 浏览 1 评论 0原文

我正在尝试更改 Cocoa 应用程序主菜单中某些项目的标题。我尝试在 IB 中设置它们,并通过我的应用程序的 applicationDidFinishLaunchingWithOptions: 方法以编程方式设置它们。无论哪种方式,我的 NSMenuItem 对象的 title 属性都会改变。但当应用程序运行时,我的任何更改都不会反映在屏幕顶部项目的实际标题中。

谁能解释一下发生了什么事吗?我该如何改变这一点?

编辑:数据结构是IB设置的默认结构:

NSApplication *app = [NSApplication sharedApplication];
NSMenu *mainMenu = [app mainMenu];
NSArray *itemArray = [mainMenu itemArray];
NSMenuItem *firstItem = [itemArray objectAtIndex: 0];
NSMenu *submenu = [firstItem submenu];

我已将firstItem和subMenu的标题属性更改为我想要的标题。但默认的仍然显示。

I am trying to change the titles of some of the items in my Cocoa app's main menu. I have tried setting them both within IB and also programmatically from my app's applicationDidFinishLaunchingWithOptions: method. Either way, the title property of my NSMenuItem object does change. But none of my changes are reflected in the actual title of the item at the top of the screen when the app is running.

Can anyone explain what is going on? And how can I change this?

EDIT: The data structure is the default one that IB sets up:

NSApplication *app = [NSApplication sharedApplication];
NSMenu *mainMenu = [app mainMenu];
NSArray *itemArray = [mainMenu itemArray];
NSMenuItem *firstItem = [itemArray objectAtIndex: 0];
NSMenu *submenu = [firstItem submenu];

I have changed the title properties of both firstItem and subMenu to be my desired title. Yet the default one still shows.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

-柠檬树下少年和吉他 2024-10-24 07:11:09

不要重命名项目,而是在 your-application-Info.plist 中从 ${PRODUCT_NAME} 更改“捆绑包名称”;随心所欲;此更改将反映在主菜单的应用程序菜单项的标题中。

Instead of renaming project change "Bundle name" in your-application-Info.plist from ${PRODUCT_NAME}; to whatever you want; this change will be reflected in the title of Application menu item of Main Menu.

仙气飘飘 2024-10-24 07:11:09

有时,这不起作用,因为 Cocoa 不喜欢您的标题 :-p 例如,当您选择的标题是本地化应用程序名称,但它想要显示非本地化应用程序名称时,就会发生这种情况。一个小技巧可以帮助......

NSMenu *menu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
NSString *title = @"My app name";

// Append some invisible character to title :)
title = [title stringByAppendingString:@"\x1b"];

[menu setTitle:title];

是的,这很疯狂,但最后那个额外的角色让一切变得不同。 (您也可以仅附加一个空格,但随后菜单项会增长,这可能不是您想要的。)

在 OS X 10.9.5 上测试。

另一件事:

您必须在显示窗口后执行所有这些操作。否则它就不起作用。此外,如果您在应用程序启动时执行此过程,然后在显示窗口时再次执行此过程,则它可能也不起作用。

Sometimes, this just does not work, because Cocoa doesn't like your title :-p That happens e.g. when the title you chose is the localized app name, but it wants to display the non-localized app name. A little trick can help...

NSMenu *menu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
NSString *title = @"My app name";

// Append some invisible character to title :)
title = [title stringByAppendingString:@"\x1b"];

[menu setTitle:title];

Yeah, it's crazy, but that extra character at the end made all the difference. (You may also append just a SPACE, but then the menu item grows, which is probably not what you want.)

Tested on OS X 10.9.5.

Another thing:

You have to do all of this AFTER you have showed a window. Otherwise it just does not work. Furthermore if you do this procedure at app start, and then later when the window is shown do it again, it may not work too.

若相惜即相离 2024-10-24 07:11:09

重命名项目就成功了。不过,似乎太极端了。我仍然对不太极端的解决方案感兴趣。

Renaming the project did it. Seems too extreme, though. I would still be interested in a less extreme solution.

堇色安年 2024-10-24 07:11:09

迟到总比不到好:经过深入研究,我找到了一个可行的解决方案,甚至是两个!

您可以设置带有渲染文本的菜单图像(您可以使用粗体!)

// render a string into image
let string = NSString(string: "Application Name")
let font = NSFont.boldSystemFont(ofSize: 13)
let size = string.size(withAttributes: [.font: font])
let image = NSImage(size: size)
image.lockFocus()
let rect = NSRect(origin: NSPoint(x: 0, y: 0.5), size: size)
string.draw(with: rect, options: [.usesLineFragmentOrigin], attributes: [.font: font])
image.unlockFocus()

appMenuItem.submenu?.title = " " // clear original App Name
appMenuItem.image = image // set the image instead

或者您可以更改整个进程名称,包括 Apple 菜单标题(感谢 这个答案!)

// dynamically load ApplicationServices.GetCurrentProcess
typealias GetCurrentProcessType = @convention(c) (UnsafePointer<ProcessSerialNumber>) -> OSStatus
let getCurrentProcessSym = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "GetCurrentProcess")!
let getCurrentProcess = unsafeBitCast(getCurrentProcessSym, to: GetCurrentProcessType.self)

// dynamically load ApplicationServices.CPSSetProcessName
typealias CPSSetProcessNameType = @convention(c) (UnsafePointer<ProcessSerialNumber>, UnsafePointer<Int8>) -> OSStatus
let cpsSetProcessNameSym = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "CPSSetProcessName")!
let cpsSetProcessName = unsafeBitCast(cpsSetProcessNameSym, to: CPSSetProcessNameType.self)

// Get current process serial number
var psn = ProcessSerialNumber()
getCurrentProcess(&psn)
// Change Process Name
"Custom Title".withCString { cpsSetProcessName(&psn, $0) }

Better late than never: after digging around I've found a working solution, even two!

You can set a menu image with a rendered text (you can use bold font!)

// render a string into image
let string = NSString(string: "Application Name")
let font = NSFont.boldSystemFont(ofSize: 13)
let size = string.size(withAttributes: [.font: font])
let image = NSImage(size: size)
image.lockFocus()
let rect = NSRect(origin: NSPoint(x: 0, y: 0.5), size: size)
string.draw(with: rect, options: [.usesLineFragmentOrigin], attributes: [.font: font])
image.unlockFocus()

appMenuItem.submenu?.title = " " // clear original App Name
appMenuItem.image = image // set the image instead

Alternatively you may change the whole Process Name including the Apple Menu title (thanks to this answer!)

// dynamically load ApplicationServices.GetCurrentProcess
typealias GetCurrentProcessType = @convention(c) (UnsafePointer<ProcessSerialNumber>) -> OSStatus
let getCurrentProcessSym = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "GetCurrentProcess")!
let getCurrentProcess = unsafeBitCast(getCurrentProcessSym, to: GetCurrentProcessType.self)

// dynamically load ApplicationServices.CPSSetProcessName
typealias CPSSetProcessNameType = @convention(c) (UnsafePointer<ProcessSerialNumber>, UnsafePointer<Int8>) -> OSStatus
let cpsSetProcessNameSym = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "CPSSetProcessName")!
let cpsSetProcessName = unsafeBitCast(cpsSetProcessNameSym, to: CPSSetProcessNameType.self)

// Get current process serial number
var psn = ProcessSerialNumber()
getCurrentProcess(&psn)
// Change Process Name
"Custom Title".withCString { cpsSetProcessName(&psn, $0) }
怕倦 2024-10-24 07:11:09

实际上有更好的方法来解决这个问题。您的项目中将会有一个 Main.strings 文件,其中包含应用程序的 MenuItems 的所有字符串,您可以直接转到那里并根据您的要求进行更新。通过这种方式,我们还可以支持本地化,而无需更改代码级别。

There is actually a better way to address this issue. There will be a Main.strings file in your project which contains all the strings for MenuItems for the application, you can directly go there and update as per your requirements. This way we can also support localization with out code level changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文