NSDocument and keyboard (like keyDown) - objective-c

I've tried to read on apple documentation but I can't find anywhere how to capture key event (space or other) into an NSDocument application.
With initialFirstRepsodner if I've understand well it's not possible to do.
Any idea?
thanks to all!
Andrea

I've tried to read on apple documentation but I can't find anywhere how to capture key event (space or other) into an NSDocument application.
What do you want to handle key events for? You need to implement keyDown: somewhere, but exactly where depends on what you intend to do.

If you want to capture all the events going to a window, you can subclass it and override -sendEvent:. If you want to capture all the events in the entire app, you can override the same method in an NSApplication subclass.

For first, I'd like to thank Peter for help!
I've used hotkey and this sample has been very usefull!
http://dbachrach.com/blog/2005/11/program-global-hotkeys-in-cocoa-easily/
thanks to all!
Andrea

First of all you have to create a subclass of NSWindow.
In xcode do: File -> New File -> Objective C Class.
give a name like "NSWindowMyEvents". That will create 2 files: .h & .m, go to the NSWindowMyEvents.h and make the declaration as follows:
#interface NSWindowMyEvents : NSWindow {
}
Save changes and compile (to be sure that IB reads the new header 0 if it is already open).
Open interface builder and load your nib/xib file that contains your Document/Main Window.
Ensure that the "window" outlet of the File's owner is set to your main window.
Click on your main Window (the one that you want to get events) and set its class (via Identity inspector cmd+6) to be: NSWindowMyEvents instead of NSWindow that it is now.
Save changes!
Go back to xcode and NSWindowMyEvents.m and paste the following code:
- (void)keyDown:(NSEvent *)theEvent
{
NSLog(#"keyDown!");
if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask)
{
NSLog(#"CommandKey Down!");
}
[super keyDown:theEvent];
}
Send the Event to super IF you want, to pass the event to the rest responder chain.
You are now handling keyboard Events.
Similarly you can handle any event in NSWindowMyEvent.m
Hope that helps....

I would recommend using NSUserDefaults and storing your shared global key combos and then checking keyDown: against those stored preferences and then basing your actions on what key was pressed.
ie: #define kMyKeyCommand #"i"

Related

How to get an NSDocument subclass to print custom views

What needs to be hooked up for an NSDocument subclass to call its print methods when File->Print... is chosen?
How does the File->Print menu get hooked up? (Right now the selector/action is hooked up to first responder's print method. That's in a storyboard, while my NSDocument subclass has its own xib.)
I've tried implementing all of:
-(void)print:(id)sender;
-(void)printDocument:(id)sender;
-(void)printDocumentWithSettings:(NSDictionary *)printSettings showPrintPanel:(BOOL)showPrintPanel delegate:(id)delegate didPrintSelector:(SEL)didPrintSelector contextInfo:(void *)contextInfo;
-(NSPrintOperation*)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError *__autoreleasing *)outError;
But none of them are ever called when I choose Print. Where are these methods supposed to go/who calls them? (I also tried a basic app with a custom view and didn't have luck there either.)
Okay. Looks like the problem is due to a bug in Xcode: When creating a Document based app using storyboards the file menu is by default hooked to print: and printDocument: is not available.
The strange part is that my print: call is getting hijacked somewhere along the line but I can't figure out where (at the application level, not the document, because the print dialog is a window not a sheet). printDocument: works as expected, but must be defined manually in order to hook it up.
This is for a document-based app, targeting 10.10, and using storyboards.
In the storyboard with Main Menu, add a User Defined Action for printDocument: (This is where storyboard based differs, and I feel is a bug. Xib based do not require this User Defined Action.)
Hook up the selector for File -> Print to First Responder and choose printDocument: instead of print:
Don't define printDocument: in your NSDocument subclass. If you want to, then be sure to call super or perhaps one of the methods below.
From NSDocument.h
/* The action of the File menu's Print... item in a document-based application.
The default implementation of this method merely invokes
[self printDocumentWithSettings:[NSDictionary dictionary]
showPrintPanel:YES
delegate:nil
didPrintSelector:NULL
contextInfo:NULL].
*/
- (IBAction)printDocument:(id)sender;
The default implementation of printDocumentWithSettings in turn calls printOperationWithSettings, so you can use either of those methods to draw custom information prior to the print sheet appearing.
The accepted solution of setting the menu item to -printDocument: is correct, but not (technically) because of an Xcode bug. (It is very a poor default setting, though.)
The menu item is calling the -print: of the whatever is the first-responder. NSView implements -print:, so if anything has been set as first-responder you will print with NSView's -print:, not your document's -print:. If editing your document requires text editing, the control you are using to implement editing will be set to first-responder, and that control will get the -print:.
Take a look at the TextEdit sample code from Apple (https://developer.apple.com/library/mac/samplecode/TextEdit/Introduction/Intro.html)
In my non-document based app I have set a custom action for the print menu item. In that method I notified my controller about the print operation via NSNotificationCenter. Maybe that works for you too :)

Define a controller for NSDocument for document-based application

I'm not very sure how Document-Based Applications works.
I've created some actions for NSObject in the Mainmenu.xib. One of this is called when the user click on "File>new":
-(IBAction) newDocument:(id)sender{
Document* newDoc =[[Document alloc] init];
[[NSDocumentController sharedDocumentController]addDocument:newDoc];
[newDoc addWindowController: [[NSWindowController alloc] initWithWindowNibName:[newDoc windowNibName] owner:newDoc]];
[newDoc showWindows];
}
I've also this code inside the openDocument:(id) sender action that does the same but of course loading data to define the application workspace.
If I run the application it show a blank document without to call newDocument action. I don't know how to stop default blank document and to set newDocument: to be called.
Then if i do openDocument: too (so I've two documents, one blank and one not) and I do some operation on the second document it also replicate in the first blank one.
I've double check delegates, file owners, and also if the - (void)windowDidBecomeMain:(NSNotification *)notification return different pointers and all seem to be ok.
Probably I've not understood document based application work flow but I've read the Apple guide and other istructions. What do I miss?
An IBAction method is called, when the user did something. So this is not called from the system at app launch.
You can customize the behavior at app launch with -applicationShouldOpenUntitledFile: (NSApplicationDelegate) and – this is probably your next question – -applicationShouldHandleReopen:hasVisibleWindows: (NSApplicationDelegate). Changing the behavior in both cases is not recommended.
Looking to your action method, I see no reason, why you want to customize it.
A instance of your document class is created automatically.
You can create a window controller for it in your document subclass. This is documented.
Just let NSDocumentController do the work for you. What is the problem of the default behavior?
No. I thought to be confused instead the only problem was about releasing observer notification. When you call the close message for a NSDocument notification observers still persist. Working in ARC I miss this point.
So This is the solution at my issue. Thank you anyway.

Cocoa - capturing specific events

I'm fairly new to Cocoa programming, and have a question about control event handling.
I create an 'action' for a button, and get an updated AppDelegate.m to handle this eg.
- (IBAction)seedBtnPressed:(id)sender {
NSString* myString = #"Hi there";
[_updateLbl setStringValue:myString];
}
When running this, pressing the 'seed' button does what it should - the label updates.
My question is: why have I captured the 'button press event' by default, as I don't see any place where I've specified this. Alternately, how would I capture a mouse-over event with an action? I gather I'd create another action for the button, but am not sure how to specify this to handle 'mouse-over' events only? Sorry if I've used Windows terminology here, I understand Cocoa uses different names for things.
Thanks
Pete
You need to Subclass the NSButton class (or even better the NSButtonCell class).
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
They should get called when the mouse enter and exit the area. You may also need to re create the tracking area, look here:
- (void)updateTrackingAreas
For fade in and fade out effect I played with animator and alpha value for example:
[[self animator]setAlphaValue:0.5];
To get mouse-over events for an NSView you should use the NSTrackingArea class (assuming you're targeting a relatively modern version of OS X). Apple have good documentation on this available at http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html
For your other query about the seedBtnPressed: triggering although you don't specify it - have you set an action in Interface Builder for the button rather than programmatically?

Why cant I see all available methods or properties present in a Class in XCode?

I am noob to XCode and Obj-C world, so pardon me for my naive question.
Following a tutorial, I was writing a basic program in Cocos2D that would accept touch input.
And one of the task was to add implement ccTouchBegan method, but that would not show up in XCode's code sense.
I wanted to implement this method
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
but I would find only this one (related to touch began)
-(BOOL) ccTouchesBeganWithEvent:(*)event
Now that I a noob, how do I explore list of all available methods and properties for a particular Class?
The image shows list of available methods that starts with ccT. ccTouchBegan and ccTouchEnded showed up because I have implemented them already. Else, they would not show just like ccTouchCancelled and ccTouchMoved events didn't show up.
How do I see all available methods & properties of a Class or Object?
To see all the available methods & properties just press Ctrl+Space
Option+Click on the object (in this case, that would be the delegate name in the header file between the < >). A small help popup will appear. Click the blue text inside the popup and the Organizer window will open at the documentation for the Class. The Documentation has all methods and properties you can use.
Just press Backspace 3 times to delete the ccT you typed in. The list will increase with every character you erase. The full list not only shows methods, as you will see.
Maybe it does not show up because you have already defined it in your code? That would be logical, as double implementation would lead to a compiler error.

tying a UISearchBar into an action

To let you know from the beginning, I am a newbie at iPhone development, and I have taken an a monstrous task.
First of all, I am writing an application that allows to you to online shop. We have an affiliate account with a known online shopping website, are trying to tie our app into searching that site, and putting the results into a table, with hyperlinks to the site, etc.
But first problems first, one thing at a time:
In Interface Builder, I have a Search Bar, and an outlet connected to the search bar. I also have an IBAction made just to take the text that is entered into the search bar, storing it into a variable, and then searching this website (yes, that's a lot of stuff for an action).
Because I am so new at this process with IB, how do I connect the Search Bar with the IBAction? I know, stupid question.
Assuming you don't have a specific SEARCH button, set your View Controller as the delegate for UITextField and implement your action on
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// Code here...
return YES;
}
Don't forget to declare the protocol in your interface file too
#interface ... : ... <UITextFieldDelegate>
Once that's done, everytime the GO/SEARCH key is pressed on the keyboard, it will call the method above.
[EDIT]
Here's the apple Doc for your reference http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITextFieldDelegate_Protocol/UITextFieldDelegate/UITextFieldDelegate.html
You can set your view controller as the search bar's delegate in IB (or programmatically), and implement the UISearchBarDelegate protocol to define actions for your search bar.
As a beginner, you should familiarize yourself with the delegate pattern, since a lot of the iOS SDK relies on it (the iOS Application Programming Guide is a good place to start).
Update
You need to implement the UISearchBarDelegate methods in your search bar's delegate. For example, if your search bar is a property of MyViewController, you probably want to have this line in MyViewController's implementation:
[self.searchBar setDelegate:self];
It's as simple as that; now, as long as you have those methods implemented in MyViewController, they will automatically get called when the related action occurs.