I am doing my first mac application. I have added my menus and customized. What is my problem is that I need some customizations in the about view. While the about menu clicked, automatically a view will pops up with details Name, Icon, copyright string, version etc. fetched from application plist. About menu in XCode application, which has buttons for Acknowledgment and Licensee Agreement. In chrome About Chrome will create a new tab in the webpage and details are shown. How this possible? Any help is appreciated.
It seems that you can do it in your MainMenu.xib, change to the target-action of the menu item About myApp to your custom action.
See the doc:
Connecting Menu Items Across Nib Files
The items in an OS X application’s menu bar often need to interact
with many different objects, including your application’s documents
and windows. The problem is that many of these objects cannot (or
should not) be accessed directly from the main nib file. The File’s
Owner of the main nib file is always set to an instance of the
NSApplication class. And although you might be able to instantiate a
number of custom objects in your main nib file, doing so is hardly
practical or necessary. In the case of document objects, connecting
directly to a specific document object is not even possible because
the number of document objects can change dynamically and can even be
zero.
Most menu items send action messages to one of the following:
A fixed object that always handles the command
A dynamic object, such as a document or window
Messaging fixed objects is a relatively straightforward process that
is usually best handled through the application delegate. The
application delegate object assists the NSApplication object in
running the application and is one of the few objects that rightfully
belongs in the main nib file. If the menu item refers to an
application-level command, you can implement that command directly in
the application delegate or just have the delegate forward the message
to the appropriate object elsewhere in your application.
If you have a menu item that acts on the contents of the frontmost
window, you need to link the menu item to the First Responder
placeholder object. If the action method associated with the menu item
is specific to one of your objects (and not defined by Cocoa), you
must add that action to the First Responder before creating the
connection.
After creating the connection, you need to implement the action method
in your custom class. That object should also implement the
validateMenuItem: method to enable the menu item at appropriate times.
For more information about how the responder chain handles commands,
see Cocoa Event Handling Guide.
Related
The system supplied text menu works by sending a number of messages like changeFont: modifyFont: and addFontTrait: up the first responder chain until it reaches an NSTextView for example.
I'd like to extend this to control row styles in my NSOutlineView but I have only been able to override changeFont: in my window controller and intercept the message (maybe a better place to do this but it works for now). This works for changing fonts but the other menu items like Bold, Bigger, Smaller which use modifyFont: and addFontTrait: aren't ever getting called in the window controller so I can't modify their behavior to work on the outline view. Interestingly they appear selectable in the menu but only changeFont: is called and as I understand it I need to get a tag value from the NSMenuItem which is the sender of the methods modifyFont: and addFontTrait:.
Does anyone know how to implement this functionality by getting those other methods to be called anywhere? Thanks!
This is documented in the Cocoa Text Architecture Guide: Font Handling – Handling Font Changes. The -addFontTrait: and -modifyFont: messages are not sent up the responder chain. They are sent directly to the font manager. The font manager makes a note of the requested modifications and sends -changeFont: up the responder chain.
You should only need to implement -changeFont: as you have.
You do not get the tag from the menu item. The font manager does that. That's the source of the information that the font manager records internally.
Your -changeFont: method should call -convertFont: on the font manager, passing the current font. That method will return a new font modified as per the recorded change request. You would do that for all the fonts which should be affected. (For example, you might have a selection with multiple fonts in it.)
You do not normally have direct access to the requested modifications, such as "add the Bold trait" or "make the font bigger".
You can customize the font manager by subclassing NSFontManager and passing your subclass to +[NSFontManager setFontManagerFactory:] very early in app start-up. In your custom font manager, you can separately track the changes requested by the various action messages like -addFontTrait:. Here is where you would check the tag of the sender. Then, in your outline view you could query the properties of your the sender of -changeFont:, after verifying that it's an instance of your subclass, to determine what change(s) were requested.
Remember, though, that your custom subclass will be used throughout your app, not just for your outline view. So, your customizations should be in addition to the normal behavior of NSFontManager, not instead of, so it doesn't break stuff.
Short answer is inside the title :)
Explaining: in my MainMenu.xib I have only the Main Menu of the application, that must be same for all NSWindows I open. There is one particular NSWindowController that has, let me say, all answers about when menu item must be enabled (via cases on selector in validateUserInterfaceItem) and what to do with all actions. When NSWindow associated with that NSWindowController is currently focused, there is no problem, but as I focus on another NSWindow all menus are grayed.
I have this flow now: MainMenu is created by reference to it as Main nib into info.plist, then AppDelegate do some init stuff and create MainWinController with MainWindow, at some point MainWinController creates 1+ DetailsWinController with DetailsWindow. AppDelegate manage my custom menu by calling each time functions from MainWinController.
So, how can I force the responder chain to query always that particular NSWindowController (MainWinController)?
You don't give many details to go on, and it isn't clear what you are trying to achieve.
My first reaction is that if you want share Menu items why are you creating multiple windows rather than Views within your MainWindow?
Assuming both your MainWindow and DetailsWindow implement the same selectors you could direct Menu Actions to the First Responder
To add the DetailsWinController in the InterfaceBuilder drag an NSObject from the Object Library, then in Identity Inspector change its class to your DetailsWinController class.
If your Main Menu has different items for the DetailsWindow just connect these to the actions in that instance.
NOTE if you so this you should NOT create the DetailsWinController in code.
If you really want to do this in code you will need to add actions and targets to your menu in code.
I have a Cocoa app with a ManMenu.xib, in which the main menu is stored and different other subviews in several xibs handling different tasks of my app. So how do I make my sub-xibs or rather their NSViewControllerController receive actions from the menu?
i have an idea but I don't know if it's the right way: I subclass NSViewController and add some actions like - (IBAction)undo or - (IBAction)redo use instances of it as the files owner. Further I add a pointer to my app delegate pointing at the actual view or rather its controller and the menu sends the action to that pointer.
Wise solution?
You should hook up your menu items to the First Responder. Their action messages will then travel along the responder chain until they reach something that responds to them.
You'll need to make sure your view controller is in the responder chain by setting it as the next responder of something else in the responder chain. I would suggest the window controller.
Speaking of the window controller, you probably should be handling undo there rather than in a view controller—it would be confusing for different views in the same window to have different undo lists. The only exception I can think of would be if the controlled views correspond to document tabs, like in Photoshop or Xcode.
I'm in need of linking some buttons in a 'document based' application to the file menu (bold text, italic text, make text bigger etc.). The issue is that since its a document based application, the MainMenu.xib is a completely different XIB file than the MyDocument.xib, so I can't drag the connections in Interface Builder like I usually would. Does anyone have a workaround? Is there a way to link button actions to a separate XIB files' built in menu functions?
Zach
Generally, you use the First Responder place-holder object.
About the First Responder
"In Interface Builder, the First Responder is a proxy object that represents the first object in your application’s dynamically determined responder chain. Because the responder chain of an application cannot be determined at design time, the First Responder proxy acts as a stand-in target for any action messages that need to be directed at the application’s responder chain. Menu items commonly target the First Responder proxy. For example, the Minimize menu item in the Window menu hides the frontmost window in an application, not just a specific window, and the Copy menu item should copy the current selection, not just the selection of a single control or view. Other objects in your application can target the First Responder as well."
Also see:
Connecting Menu Items Across Nib Files
Also, if you want to create buttons whose actions are basically the same as the Format > Bold, etc. commands, see: Connecting the Font Menu in Interface Builder 3
I would like to enable the grayed out open file menu item within a non-document-based application. Document-based applications automatically give you a nice open file dialog with file extension filters based on plist entries etc... Surely, a simple elegant method exist to re-enable this functionality.
I have...
Added document types to the project properties window
Assigned my controller class as the application delegate
Added the delegate application:openFile: to my controller class
First, make sure your File->Open menu item's selector is connected to the openDocument: action of the First Responder.
Second, make sure you are responding to the action. Take a look at the Responder chain of a non-document application with an NSWindowController object. Any object within your responder chain can respond to the message, but it is best to pick the object which is the most capable and appropriate. Once you have decided which class in your responder chain is the most appropriate to handle the message, add the openDocument: action to it's implementation and write your code to respond to it accordingly.
The key is that something along the menu item's responder chain has to respond to the -openDocument: action. Normally it's the NSDocumentController. I'd take a look at how an empty document-based application sets up that menu item.