启动基于 Cocoa 文档的应用程序首先显示选择窗口
这看起来应该很容易,但我一定错过了一些东西。我有一个基于文档的应用程序。我还构建了一个新的 XIB,其中有一个 NSTableView 和三个按钮,我打算显示以前的文件列表。我希望在应用程序首次启动时显示此 XIB 而不是文档窗口。一旦用户选择旧文件或点击“新建”按钮,我希望转到文档窗口。这很常见,而且我经常看到使用。
在尝试实现此功能时,我修改了project-info.plist 文件,并将主NIB 文件基本名称从MyDocument 更改为我的Selection XIB 名称。这会导致应用程序显示“选择”窗口而不是“我的文档”窗口。到目前为止似乎还没有问题。
在我的选择窗口中,我专门为此 XIB 设置了表视图、数组控制器和自定义窗口控制器。我已将文件所有者设置为新的窗口控制器,并将窗口控制器的窗口属性绑定到窗口,将窗口的委托属性绑定到文件所有者以及“选择”、“取消”和“新建”按钮。没有任何东西与 NSApplication 绑定。但奇怪的是,当我运行这个应用程序时,它似乎想要将这些控制器连接到 NSApplication 并出现错误(其他两个按钮也相同):
Could not connect the action selectButton: to target of class NSApplication
它还显示一个错误对于保存对我的数组的引用的插座,NSApplication 不符合键值对。数组控制器、窗口和按钮未绑定到 NSApplication,而是绑定到新的窗口控制器。我本以为如果有任何问题,不会提及 NSApplication,而是提及控制器所绑定的窗口控制器。
有人知道这里发生了什么事吗?这是一个目标操作问题吗,因为我将“主 NIB 文件基本名称”从“主菜单”更改为“选择”?如果我不应该改变这个,那么我怎样才能让Cocoa允许我在显示文档窗口之前显示一个选择屏幕?
非常感谢任何帮助。 抢
This seems like it should be easy yet I must be missing something. I have a document-based application. I have also built a new XIB that has a NSTableView and three buttons on it that I intend to display a list of previous files. I wish this XIB to be displayed instead of the document window when the application first starts. Once the user selects an old file or hits the "New" button I wish to then go to the document window. This is very common and I've seen used quite often.
In my attempts to get this working I have modified the project-info.plist file and changed the Main NIB File Base Name from MyDocument to my Selection XIB name. This causes the application to display the Selection window instead of the MyDocument window. There seems to be no problem up to this point.
In my Selection window I have set up my table view and an array controller and a custom window controller just for this XIB. I have set the File's Owner to the new window controller and bound the window controller's window property to the window and the Window's delegate property to the File's Owner as well as the "Select", "Cancel", and "New" buttons. Nothing is bound to NSApplication. But the strange thing is when I run this application it seems to want to connect these controllers to NSApplication with the error (same for the other two buttons):
Could not connect the action selectButton: to target of class NSApplication
It also displays an error that NSApplication is not Key-Value compliant for the outlet that holds reference to my array. The Array Controller, Window, and buttons are not bound to NSApplication but to the new Window Controller. I would have expected that if there was any problem is would NOT mention NSApplication but rather the window controller to which the controllers are bound.
Anyone know what is happening here? Is this a Target-Action problem because I changed the "Main NIB File Base Name" from "Main Menu" to "Selection"? If I am not supposed to change this, then how can I get Cocoa allow me to display a selection screen before showing the document window?
Any help is greatly appreciated.
Rob
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
IB 中笔尖文件所有者类别的设置仅是建议性的;它让 IB 仅显示该类的实例提供的出口和操作。它并不强制文件的所有者是该类的实例,因为文件的所有者不是 nib 的一部分。
文件的所有者是加载笔尖的对象。 这必然意味着它位于笔尖之外,笔尖中的任何内容都无法决定它的任何内容。对于 MainMenu 笔尖,其文件所有者(加载 MainMenu 笔尖的对象)是NSApplication 实例。因此,您在 MainMenu 笔尖中连接到文件所有者的所有内容都连接到了应用程序对象,即使您告诉 IB 这不是应用程序。
应用程序是 MainMenu 笔尖的所有者(无论您告诉 IB 是什么)都不是错误。应用程序始终是MainMenu 笔尖的所有者。这是正常且正确的;你无法改变它,不应该尝试改变它,也不需要改变它。
简而言之,这个错误是您将一个笔尖用于两个截然不同的目的。
您应该让 MainMenu 笔尖单独存在,仅包含 MainMenu、您的自定义文档控制器(我稍后会介绍)和您的应用程序委托,并将先前的文档窗口移动到一个单独的笔尖中,该笔尖由以前的文档窗口控制器。为了让窗口控制器成为该笔尖的所有者,您需要让窗口控制器加载它。您必须在代码中执行此操作 - 无法在 IB 或 plist 中进行设置。
在应用程序的委托中,实例化并拥有窗口控制器。听起来您创建了一个自定义 NSWindowController 子类,因此您可以重写其 init 以使其向自身发送 initWithWindowNibName: 消息来加载并拥有笔尖。然后,只需使用
alloc
和init
从应用程序委托创建窗口控制器。这将消除控制台消息,并确保按钮实际上连接到窗口控制器(因为它们连接到文件所有者,通过此更改,文件所有者将成为窗口控制器)。
让您的应用程序委托通过向窗口控制器发送
showWindow:
消息来响应applicationOpenUntitledFile:
。这将使先前的文档窗口在用户通常创建新文档的任何时候出现。如果您想支持创建文档的常用方法(即允许新文档工作),请实现
applicationDidFinishLaunching:
和applicationShouldHandleReopen:hasVisibleWindows:
,而不是applicationOpenUntitledFile :。确保没有文档打开,如果是这种情况,请显示您的窗口。
您还应该创建一个 NSDocumentController 的自定义子类,并使您的文档控制器成为其实例,并在该类中实现
addDocument:
和removeDocument:
以重新显示之前的内容- 关闭最后一个打开的文档时的文档窗口,并在打开文档时隐藏它。The setting in IB for the class of the File's Owner of the nib is only advisory; it lets IB show only the outlets and actions that are provided by instances of that class. It does not enforce that the File's Owner will be an instance of that class, because the File's Owner is not part of the nib.
The File's Owner is the object that loads the nib. This necessarily means that it is outside of the nib, and nothing in the nib determines anything about it. In the case of the MainMenu nib, its File's Owner—the object that loads the MainMenu nib—is the NSApplication instance. So, everything you hooked up to the File's Owner in your MainMenu nib, you hooked up to the application object, even though you told IB that it wouldn't be the application.
That the application is the owner of the MainMenu nib—regardless of what you tell IB—is not the bug. The application is always the owner of the MainMenu nib. That is normal and correct; you cannot change it, should not attempt to change it, and don't need to change it.
The bug, in a nutshell, is that you are using one nib for two very different purposes.
You should let the MainMenu nib be that alone—containing only the MainMenu, your custom document controller (I'll get to that in a moment), and your app delegate—and move the previous-documents window into a separate nib, owned by the previous-documents window controller. In order to have a window controller be the owner of this nib, you need to have the window controller load it. You must do that in code—you cannot set that up in IB or in a plist.
In your application's delegate, instantiate and own the window controller. It sounds like you made a custom NSWindowController subclass, so you can override its
init
to have it send itself theinitWithWindowNibName:
message to load and own the nib. Then, just usealloc
andinit
to create the window controller from the app delegate.That will get rid of the console message, and ensure that the buttons are actually hooked up to the window controller (because they're hooked up to the File's Owner, which, with this change, will be the window controller).
Have your app delegate respond to
applicationOpenUntitledFile:
by sending the window controller theshowWindow:
message. This will make the previous-documents window appear any time the user ordinarily would have created a new document.If you want to support the usual methods of creating documents (i.e., allow New Document to work), then implement
applicationDidFinishLaunching:
andapplicationShouldHandleReopen:hasVisibleWindows:
, notapplicationOpenUntitledFile:
. Make sure no documents are open, and show your window if that's the case.You should also make a custom subclass of NSDocumentController and make your document controller an instance of that, and in that class, implement
addDocument:
andremoveDocument:
to re-show the previous-documents window when the last open document is closed, and hide it when a document is opened.