Here's the layout of my little test app:
AppDelegate owns WindowController.
WindowController owns CustomTextContainerView.
CustomTextContainerView owns an NSScrollView which embeds MyCustomTextView (an NSTextView subclass).
The xibs for both the standard MainMenu and my window controller are relatively empty. My window controller's -windowDidLoad looks like this:
- (void)windowDidLoad {
[super windowDidLoad];
// create CustomTextContainerView
[[self window] setContentView:self.customTextContainerView];
}
What I'm trying to do is set first responder to the textView, but I've tried everything I can think of to get this to work.
I've made it so CustomTextContainerView just forwards -becomeFirstResponder on to its textView. I've tried calling it directly on both the container and the textView but I can't get it to become first responder automatically.
Note: The user can still click in the text area and start typing, but what I'm trying to do is set first responder status automatically so I don't have to click before I start typing. What am I missing?
To force the first responder for a window, call this:
[[self window] makeFirstResponder:self.customTextContainerView];
(This assumes that everything else necessary for first-responder status is enabled, e.g. the view can't have overridden acceptsFirstResponder to return NO.)
Related
I have a simple program, for making sure the print works.
-Subclassed NSObject for a Controller, "ViewController.
-Subclassed NSView, View
Added a custom view to the window, set class to View.
Made ViewController delegate for View.
Added Object in IB, set class to ViewController.
Added IBOutlet to Delegate section of ViewController, connected it to the the custom view on the window.
In View, have a simple [myString drawInRect: rect], where myString is defined in the init as #"Hi".
When I run, the program prints "Hi" in the view. When I click the "Print" menu item, the print preview shows the entire window.
More: I hade an earlier test program which had no print code, I ran it and the print preview showed only the view. I've got through both codes and cannot find a difference, so I am lost at why one is working and the other is not.
Do any of you know why the print preview would show the entire window instead of the view?
[EDIT]-----
I also created an extremely simple program to check and have the same issue.
Subclassed NSView, MainView
Added Custom View to Window, set class to MainView
Added [str drawInRect: dirtyRect withAttributes:nil];
(note; NSString *str = #"Hello";).
[More Information]-------
I added a print method as follows to the NSView object:
-(void)printPDF{
NSRect r = [self bounds];
[[NSPrintOperation printOperationWithView:self] runOperation];
[self dataWithPDFInsideRect:r];
}
Added a button to the window, linked it to an IBAction method in the ViewController:
-(IBAction)printToPDF:(id)sender{
[view printPDF];
}
In the ViewController I have:
IBOutlet View *view;
This works! So, why does the default "print" menu item print the entire Window?
By default, you don't have to write any printing code and the printing just works. But, it provides default behavior (aka, print the entire window).
If you want custom printing behavior, you'd have to write your own printing method.(like you did in your extremely simple program). And you can link the default print menu item to your own printing method.
I'm using NSWindowController to load a window from a NIB. However, when I call showWindow:, the window is visually topmost, but the focus remains where it was (instead of moving it to the new window).
It's easy to see this happening when the first window (with keyboard focus) is moved slightly, before creating the new window (via cmd+n). This is the result:
The bottom, focused window is the original window. The unfocused window on top is the newly created window.
This is the relevant code:
AppDelegate.h:
- (IBAction)newDocument:(id) sender;
AppDelegate.m:
- (IBAction)newDocument:(id) sender {
[[[FooController alloc] init] showWindow:self];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self newDocument:self];
}
FooController.h:
#interface FooController : NSWindowController { }
#end
FooController.m:
- (id)init {
self = [super initWithWindowNibName:#"FooWindow"];
return self;
}
FooWindow.xib:
A freshly created Window xib, without modifications.
MainMenu.xib:
The default MainMenu.xib, with its window deleted.
Calling makeKeyAndOrderFront: on the window in the controller's windowDidLoad method does not appear to focus the new window. Setting the File's owner of FooWindow.xib to FooController also did not appear to help.
What is the correct way to load and show a window from a NIB so that it does receive keyboard focus?
Edit: It looks like NSWindowController's window method returns nil, which explains why calling methods on window doesn't do anything. But why is it nil?
Okay, I found the cause of this problem.
The xib's File's owner must be set to the controller, and (this is the part I didn't know about) you have to connect the controller's window outlet to the window itself.
Having done that, it just works. No makeKeyWindow, makeMainWindow or makeKeyAndOrderFront: needed.
Perhaps makeMainWindow: or makeKeyWindow: helps
I have to upgrade one existing application and neeed to split its existing UI into separate NIBs. I have planning to start with creating separate NIBs and NSViewController for all my splitted UIs. Now the problem is my NSViewController didn't respond on keyboard TAB and SHFIT+TAB events, I simply wants my NSViewController to set focus on appropriate child control in my dynamically loaded NSViewController view when user click TAB or SHIFT+TAB.
Thanks,
EDITED :
Following is my requirement.
I have three sub views which i need to load dynamically and switch using NSPopupButton in my MainWindow placeholder NSBox.
For checking i have created new cocoa app and added one NSPopupButton and NSBox to Window and join the outlets for NSPopupButton and NSBox.
Second, I have created three new NSViewController's with three different NIB's containing separate custom view containing two or three NSTextField's child controls.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
}
In the main app delegate function i am adding all the three NSViewController's to an array and later swapping of views using replaceSubview to replace views in placeholder NSBox.
I have added following code in all the three NSViewController's, but i am still not getting focus on child controls by pressing TAB or SHIFT+tab keys.
- (void)loadView {
[super loadView];
// store the responder that’s right after the view in the responder chain
NSResponder *nextResponder = [[self view] nextResponder];
// set the view controller (self) as the next responder after the view
[[self view] setNextResponder:self];
// set the stored responder as the next responder after the view controller
[self setNextResponder:nextResponder];
}
Even though NSViewController inherits from NSResponder, Cocoa doesn’t automatically add NSViewController instances to the responder chain. You need to do it yourself.
One possible solution is to insert your view controller into the responder chain between the view it is controlling and the next responder of that view. For instance, in your view controller implementation,
- (void)loadView {
[super loadView];
// store the responder that’s right after the view in the responder chain
NSResponder *nextResponder = [[self view] nextResponder];
// set the view controller (self) as the next responder after the view
[[self view] setNextResponder:self];
// set the stored responder as the next responder after the view controller
[self setNextResponder:nextResponder];
}
I am using a custom subclass of NSDocument and a custom subclass of NSWindowController. The problem is that I cannot reference my custom document from my custom window controller.
In IB, in the TKDocument NIB I have File's Owner set to TKWindowController.
In my TKDocument subclass I have:
- (void) makeWindowControllers {
TKWindowController *controller = [[TKWindowController alloc] init];
[self addWindowController:controller];
}
Then in my TKWindowController subclass I overrode setDocument to make sure it was being called:
- (void) setDocument(NSDocument *) document {
NSLog(#"setDocument:%#", document);
[super setDocument:document];
}
and then (again in TKWindowController) my action which references the document itself:
- (IBAction) plotClicked:(id) sender {
TKDocument *doc = [self document];
NSLog(#"plotClicked %#", doc);
}
The NSLog in setDocument outputs the string returned by my [TKDocument description] override as I'd expect; I only put it there to see if it was being called. However, doc in plotClicked is null.
What might I have done wrong?
EDIT: I believe the problem is to do with NIBs. My Document has its own NIB with File's Owner set to the custom controller as mentioned above. The plotClicked action is fired from a menu item in MainMenu.xib. I believe it's hitting a new instance of the controller which isn't associated with the current, active document.
So, how do I link the two? My question is really this: How do I obtain a handle to the current active document (or its windowcontroller) from MainMenu.xib?
Thanks
My Document has its own NIB with File's Owner set to the custom controller as mentioned above.
The File's Owner of a document nib should be the document. Consider that suspect #1.
The plotClicked action is fired from a menu item in MainMenu.xib. I believe it's hitting a new instance of the controller which isn't associated with the current, active document.
Did you put a window controller inside your main menu nib? If not, then that isn't the problem, since you must have wired up your plotClicked: menu item to the First Responder, and the window controller and its document will be in the responder chain.
If you did, then there's the solution: delete the window controller from the MainMenu nib and hook up your menu item to the First Responder, so that the action message goes down the responder chain, which will enable it to hit the document or window controller.
How do I obtain a handle to …?
The only Handles on the Mac come from Carbon; those Handles do not exist in Cocoa.
init is not a designated initializer of NSWindowController. You want one of these: – initWithWindow:, – initWithWindowNibName:, – initWithWindowNibName:owner:, or – initWithWindowNibPath:owner:.
Also, from the docs:
In your class’s initialization method,
be sure to invoke on super either one
of the initWithWindowNibName:...
initializers or the initWithWindow:
initializer. Which one depends on
whether the window object originates
in a nib file or is programmatically
created.
Normal OSX applications eat the first mouse click when not focused to first focus the application. Then future clicks are processed by the application. iTunes play/pause button and Finder behave differently, the first click is acted on even when not focused. I am looking for a way to force an existing application (Remote Desktop Connection.app) to act on the first click and not just focus.
Check NSView's acceptsFirstMouse, it may be what you're looking for.
acceptsFirstMouse:
Overridden by subclasses to return YES if the receiver should be sent a mouseDown: message for an initial mouse-down event, NO if not.
(BOOL)acceptsFirstMouse:(NSEvent *)theEvent
Parameters
theEvent
The initial mouse-down event, which must be over the receiver in its window.
Discussion
The receiver can either return a value unconditionally or use the location of theEvent to determine whether or not it wants the event. The default implementation ignores theEvent and returns NO.
Override this method in a subclass to allow instances to respond to click-through. This allows the user to click on a view in an inactive window, activating the view with one click, instead of clicking first to make the window active and then clicking the view. Most view objects refuse a click-through attempt, so the event simply activates the window. Many control objects, however, such as instances of NSButton and NSSlider, do accept them, so the user can immediately manipulate the control without having to release the mouse button.
Responding to the first mouse click when not focused is called 'click through'. And its worth is debated heatedly, for instance here and here.
// Assuming you have 1 view controller that's always hanging around. Over ride the loadview. N.B. this won't work pre-yosemite.
- (void)loadView {
NSLog(#"loadView");
self.view = [[NSView alloc] initWithFrame:
[[app.window contentView] frame]];
[self.view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea0 = [[NSTrackingArea alloc] initWithRect:self.view.bounds
options:opts
owner:self
userInfo:nil];
[self.view addTrackingArea:trackingArea0];
}
- (void)mouseEntered:(NSEvent *)theEvent {
NSLog(#"entered");
if ([[NSApplication sharedApplication] respondsToSelector:#selector(activateIgnoringOtherApps:)]) {
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
}