xcode 如何在我的 Cocoa 应用程序中修改自动生成的关于窗口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8500099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I modify the automatically generated About window in my Cocoa app?
提问by simon.d
A menu item for "About MyApp" was automatically created for me and it displays an about window. How do I edit this window? I'd like to add some extra stuff there but I can't find the xib anywhere.
“关于 MyApp”的菜单项是自动为我创建的,它显示一个关于窗口。如何编辑此窗口?我想在那里添加一些额外的东西,但我在任何地方都找不到 xib。
Thanks!
谢谢!
回答by Michael Robinson
Modify the contents of Credits.rtf
file located inside the 'supporting files' group of your project.
修改Credits.rtf
位于项目“支持文件”组内的文件内容。
回答by Nicolas Miari
A menu item for "About MyApp" was automatically created for me and it displays an about window.
“关于 MyApp”的菜单项是自动为我创建的,它显示一个关于窗口。
This is standard with Xcode templates for Cocoa apps. Keep reading to see how it is wired.
这是 Cocoa 应用程序的 Xcode 模板的标准。继续阅读以了解它是如何接线的。
How do I edit this window? I'd like to add some extra stuff there but I can't find the xib anywhere.
如何编辑此窗口?我想在那里添加一些额外的东西,但我在任何地方都找不到 xib。
There is no xib: This window is created at runtime by the application object ([NSApplication sharedApplication]
), when it receives the message orderFrontStandardAboutPanelWithOptions:
, which that menu item sends when selected (as you an verify in the Connections Inspector in Interface Builder).
没有 xib:此窗口由应用程序对象 ( [NSApplication sharedApplication]
)在运行时创建,当它收到消息时orderFrontStandardAboutPanelWithOptions:
,该菜单项在选择时发送(作为您在 Interface Builder 中的 Connections Inspector 中的验证)。
By default (as others have mentioned), it loads the contents to display from a file named "Credits.rtf" if such file exists within your app bundle's resources; otherwise it grabs basic info from your app's Info.plist entries:
默认情况下(正如其他人所提到的),它会从名为“Credits.rtf”的文件加载要显示的内容,如果此类文件存在于您的应用程序包的资源中;否则它会从您应用的 Info.plist 条目中获取基本信息:
- App name
- Bundle version
- Copyright notice
- 应用名称
- 捆绑版
- 版权声明
What you can do is override this behaviour as follows:
您可以做的是按如下方式覆盖此行为:
- Create a custom "About" window in Interface builder, with all the subviews and labels you want. Name the file "AboutWindow.xib".
Create a custom
NSWindowController
subclass, initialized with your custom window's nib name and set as the nib's owner:- (instancetype) init { if(self = [super initWithWindowNibName:@"AboutWindow" owner:self]){ // (other initialization...) } return self; }
Connect your About window's subviews to outlets in the window controller class. Also, specify the class for File Owner as your custom NSWindowController subclass and connect the window's "New Referencing Outlet" to File Owner's
window
property.- Go to MainMenu.xib in Interface Builder. Remove the action that is wired to the menu item "About ...", and re-wire a new one to the
about:
method of the placeholder object "First Responder". In your app delegate, add an instance variable to hold your window controller so it does not get deallocated right away (alternatively, make your window controller class a singleton and use the shared instance):
@implementation AppDelegate { AboutWindowController *_aboutwindowController; }
Still in AppDelegate, implement the method
about:
that you wired in step 3, like this:- (IBAction)about:(id)sender { if (_aboutwindowController == nil) { _aboutwindowController = [AboutWindowController new]; } [_aboutwindowController.window orderFront:self]; }
...or, if your view controller is implemented as a singleton, like this:
- (IBAction)about:(id)sender { [[AboutWindowController defaultController].window orderFront:self]; }
Finally, in order for your window controller to correctly display your app's information, read the relevant keys from the Info.plist file, like this (actual outlet ivars will be different in you case):
- (void)windowDidLoad { [super windowDidLoad]; // Implement this method to handle any initialization after your window // controller's window has been loaded from its nib file. NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; self.appNameLabel.stringValue = [infoDictionary objectForKey:@"CFBundleName"]; self.appVersionLabel.stringValue = [infoDictionary objectForKey:@"CFBundleShortVersionString"]; self.appCopyrightLabel.stringValue = [infoDictionary objectForKey:@"NSHumanReadableCopyright"]; }
- 在界面构建器中创建一个自定义的“关于”窗口,其中包含您想要的所有子视图和标签。将文件命名为“AboutWindow.xib”。
创建一个自定义
NSWindowController
子类,使用自定义窗口的笔尖名称初始化并设置为笔尖的所有者:- (instancetype) init { if(self = [super initWithWindowNibName:@"AboutWindow" owner:self]){ // (other initialization...) } return self; }
将关于窗口的子视图连接到窗口控制器类中的出口。此外,将文件所有者的类指定为您的自定义 NSWindowController 子类,并将窗口的“新引用插座”连接到文件所有者的
window
属性。- 转到 Interface Builder 中的 MainMenu.xib。删除连接到菜单项“关于...”的操作,并将一个新的操作重新连接到
about:
占位符对象“First Responder”的方法。 在您的应用程序委托中,添加一个实例变量来保存您的窗口控制器,这样它就不会立即被释放(或者,将您的窗口控制器类设为单例并使用共享实例):
@implementation AppDelegate { AboutWindowController *_aboutwindowController; }
仍然在 AppDelegate 中,实现
about:
您在步骤 3 中连接的方法,如下所示:- (IBAction)about:(id)sender { if (_aboutwindowController == nil) { _aboutwindowController = [AboutWindowController new]; } [_aboutwindowController.window orderFront:self]; }
...或者,如果您的视图控制器是作为单例实现的,如下所示:
- (IBAction)about:(id)sender { [[AboutWindowController defaultController].window orderFront:self]; }
最后,为了让您的窗口控制器正确显示您的应用程序信息,请从 Info.plist 文件中读取相关键,如下所示(实际插座 ivars 在您的情况下会有所不同):
- (void)windowDidLoad { [super windowDidLoad]; // Implement this method to handle any initialization after your window // controller's window has been loaded from its nib file. NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; self.appNameLabel.stringValue = [infoDictionary objectForKey:@"CFBundleName"]; self.appVersionLabel.stringValue = [infoDictionary objectForKey:@"CFBundleShortVersionString"]; self.appCopyrightLabel.stringValue = [infoDictionary objectForKey:@"NSHumanReadableCopyright"]; }
You might be tempted to read the app icon from the bundled resources too, but there's a more elegant way that works even if you didn't specify an icon and are stuck with the default "Ruler + Pencil + Brush over a Sheet" app icon: Grab the runtime icon image using the following code:
您可能也想从捆绑的资源中读取应用程序图标,但即使您没有指定图标并坚持使用默认的“标尺 + 铅笔 + 在工作表上刷”应用程序图标,也有一种更优雅的方式可以工作:使用以下代码获取运行时图标图像:
self.appIconImageView.image = [NSApp applicationIconImage];
I have put together a demo project on Githubthat shows this and further customizations of the About window.
我在 Github 上整理了一个演示项目,展示了这个和关于“关于”窗口的进一步自定义。
UPDATE:I have added a Swift versionof the demo projectto the Github repository.
更新:我添加了一个斯威夫特版本中的演示项目到GitHub的仓库。
It features:
它的特点是:
- Swift 4 (now that Xcode 9 is official)
- Storyboards instead of xibs
- Moved all the outlets to the new viewcontroller, kept window appearance code in the windowcontroller.
- Swift 4(现在 Xcode 9 是正式版本)
- 故事板而不是xibs
- 移动所有的出口到新的视图控制器,保持窗口外观代码在窗口控制器。