6

我正在尝试更改 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 的标题属性更改为我想要的标题。然而,默认的仍然显示。

4

4 回答 4

7

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

于 2012-02-26T22:42:26.777 回答
6

有时,这只是行不通,因为 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 上测试。

另一件事:

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

于 2014-11-27T08:34:43.333 回答
0

重命名项目做到了。不过好像太极端了。我仍然会对不太极端的解决方案感兴趣。

于 2011-02-12T17:35:15.010 回答
0

迟到总比没有好:在四处挖掘之后,我找到了一个可行的解决方案,甚至两个!

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

// 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) }
于 2021-09-02T15:24:08.600 回答