I am using the following code to deselect an NSTextView, as suggested here. Unfortunately, nothing at all happens. I have tried what I know to debug it, but everything seems to be working correctly, but it doesn't affect the NSTextView.
The code:
// Sets the scrolling bounds and behavior. This might be useful, but I don't know
[[textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[[textView textContainer] setWidthTracksTextView:FALSE];
// The code for deselecting, beginning by making sure it is actually selected (for testing only, as strange as it is)
[textView setSelectable:TRUE];
[textView setDelegate:self];
[_window makeFirstResponder:textView];
NSText *fieldEditor = [_window fieldEditor:TRUE forObject:textView];
[fieldEditor setSelectedRange:NSMakeRange([[fieldEditor string] length],0)];
[fieldEditor setNeedsDisplay:YES];
Any ideas about why this doesn't work? I am sure my outlets are set properly because I can manipulate other things, such as it's string value.
I'm not sure NSTextViews use the field editor, have you tried calling the method on the text view directly?
[textView setSelectedRange:NSMakeRange(textView.string.length, 0)];
The range location can be adjusted to move the cursor to the start or end, for example. You may also want to check to make sure something is actually selected before calling this method.
EDIT:
From your comment it sounds like you just want it to resign first responder. You can do that manually by calling [textView.window makeFirstResponder:nil];
This almost worked for me;
[textView.window makeFirstResponder:nil];
However, I had trouble setting the first responder to nil. If I set it to any other view it seems to do as you want.
[textView.window makeFirstResponder:[textView superview]];
Tested in 10.7 Lion.
I've using this approach and it works perfectly:
[textView setSelectedRange:NSMakeRange(0, 0)];
As suggested earlier setSelectedRange: will do the trick BUT!
If your goal is to completely remove the selection and the cursor too, f.e. if you subclass an NSTextView to support similar behavior like NSTextEdit has in case of firstResponder status change you should write:
- (BOOL)resignFirstResponder
{
// Invalid range location will remove cursor too
[self setSelectedRange:NSMakeRange(NSUIntegerMax, 0)];
return YES;
}
//------------------------------------------------------------------------------
- (BOOL)becomeFirstResponder
{
[self setSelectedRange:NSMakeRange(0, self.string.length)];
return YES;
}
//------------------------------------------------------------------------------
[textView setDelegate:self];
I have a feeling that one of your delegate methods is preventing things from happening. See the documentation under "Managing the selection".
As a temporary solution, just until somebody comes up with a better idea, setHidden: can be used. I am sure this is not as efficient as is recommended, but it deselects the NSTextView.
Simply toggle it twice, like so:
[textView setHidden:TRUE];
[textView setHidden:FALSE];
Related
I have an NSTextView inside an NSScrollView. I put text in the NSTextView and scroll it to the bottom programatically, which works OK, but the scrollbar stays at the top. Using the mouse to position the scrollbar causes it to jump to the bottom, where it belongs, and from that point it operates OK.
My code:
textView.string = s;
[textView scrollToEndOfDocument:self];
Don't get hung up on the scrollToEndOfDocument method--I also tried:
[textView scrollRangeToVisible:NSMakeRange(s.length, 0)];
and:
[[scrollViewText contentView] scrollToPoint:NSMakePoint(0, textView.frame.size.height)];
[scrollViewText reflectScrolledClipView:[scrollViewText contentView]];
with exactly the same problem, shown here:
I fixed the problem by adding one line:
textView.string = s;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]];
[textView scrollToEndOfDocument:self];
That runUntilDate call shouldn't be necessary. My theory is that it gives the NSScrollView a chance to catch up and synchronize itself, somehow.
This is all on Lion. I tried it with the System Preference set to both the Lion "backwards" scrolling and the the traditional pre-Lion scrolling, with identical results.
Any ideas about:
Why that call I added helped, and
How to make it work without that call?
Try NSScrollView's reflectScrolledClipView:
Edit: How about replacing
[[scrollViewText contentView] scrollToPoint:NSMakePoint(0, textView.frame.size.height)];
with
[scrollView.contentView scrollToPoint:NSMakePoint(0, scrollView.documentView.frame.size.height-scrollView.contentSize.height)];
Because as it stands I believe you're scrolling past the document view's frame.
In most systems, the default behaviour for "open a new window" is that it appears at the front. This doesn't happen in Cocoa, and I'm trying to find the "correct" way to make this standard behaviour. Most things I've tried only work for a maximum of one window.
I need to open multiple windows on startup:
(N x NSDocuments (one window each)
1 x simple NSWindowController that opens a NIB file.
Things that DON'T work:
Iterate across all the NSDocuments I want to open, and open them.
What happens? ... only the "last" one that call open on comes to the front - the rest are hidden, invisible, nowhere on the screen, until you fast-switch or use the Window menu to find them.
Code:
...documents is an array of NSPersistentDocument's, loaded from CoreData...
[NSDocumentController sharedDocumentController];
[controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error];
Manually invoking "makeKeyAndOrderFront" on each window, after it's opened
What happens? nothing different. But the only way I can find to get the NSWindow instance is so horribly hacky it seems totally wrong (but is mentioend in several blogs and mailing list posts)
Code:
[NSDocumentController sharedDocumentController];
NSDocument* openedDocument = [controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error];
[[[[openedDocument windowControllers] objectAtIndex:0] window] makeKeyAndOrderFront:nil];
...I know I'm doing this wrong, but I can't find out why/what to do differently :(.
Something that works, usually, but not always:
As above, but just use "showWindow" instead (I took this from the NSDocument guide).
Bizarrely, this sometimes works ... even though it's the exact code that Apple claims they're calling internally. If they're calling it internally, why does it behave different if I re-invoke it after they've already done so?
[[[openedDocument windowControllers] objectAtIndex:0] showWindow:self];
You can just open all the documents without displaying and then tell the documents to show their windows:
NSArray* docs = [NSArray arrayWithObjects:#"doc1.rtf", #"doc2.rtf",#"doc3.rtf",#"doc4.rtf",nil];
for(NSString* doc in docs)
{
NSURL* url = [NSURL fileURLWithPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:doc]];
NSError* err;
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:NO error:&err];
}
[[[NSDocumentController sharedDocumentController] documents] makeObjectsPerformSelector:#selector(showWindows)];
Won't this work?
For 10.6 or greater
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
This often has something to do with the app itself: your other windows are behind other apps (in particular, behind Xcode!), and would have appeared with a Hide Others command.
The solution to that problem would be that after you send showWindow to all of your windows (making sure you do the key one last), you tell the app to come forward, relative to other apps.
NSApp.activateIgnoringOtherApps(true) // Swift
or
[NSApp activateIgnoringOtherApps:YES]; // Objective-C
See also: How to bring NSWindow to front and to the current Space?
I have an NSMenu in the Mac statusbar, inside it I have a load of NSMenuItems and a custom view. Inside the custom view I have an NSTextField. I want to set the focus on the NSTextField when the menu is opened as in the Spotlight menu so the user can type straight away.
I have tried quite a few methods including:
[myTextField becomeFirstResponder];
and
[myTextField selectText: self];
[[myTextField currentEditor] setSelectedRange:NSMakeRange([[myTextField stringValue] length], 0)];
but none of them work.
Thanks
Alex
You were on the right track with the first one, but -becomeFirstResponder doesn't actually make your view the first responder--you have to call -[NSWindow makeFirstResponder:] for that.
Google suggests that NSMenus actually have an attached window. You have to use it very carefully, but it is safe to call makeFirstResponder: on it.
More information about this and how to take advantage of it here: https://web.archive.org/web/20171113100008/http://www.cocoabuilder.com/archive/cocoa/195835-set-focus-on-nsview-in-an-nsmenuitem.html
I know how I'd do this with NSTextView, but NSTextField doesn't seem to provide a way to access the NSTextStorage backing it, so I can't set myself as a delegate and process -textStorageDidProcessEditing:.
I have a NSTextField as part of a sheet. If that text field is emtpy at any point, the OK button should be disabled until some input is provided. That's basically all I'm looking to do, and I'm sure there's a really simple way to do this?
I tried:
[[[filenameInput cell] textStorage] setDelegate:self];
Thinking that NSTextFieldCell would provide the text storage (mostly since Xcode kindly auto-completed it for me) and then of course, did my validation via the delegate method:
-(void)textStorageDidProcessEditing:(NSNotification *)notification {
BOOL allowSubmit = ([[filenameInput stringValue] length] > 0)
&& (([relativePathSwitch state] == NSOnState) || ([[localPathInput stringValue] length] > 0));
[createButton setEnabled:allowSubmit];
}
This compiles but causes a runtime error as NSTextFieldCell does not respond to textStorage.
What's the standard pattern I should be following here? This must be one of those "every day" tasks for Cocoa devs, I imagine :)
This is what NSFormatter is for; create a subclass of NSFormatter and set an instance of it as your NSTextField's formatter, and let it validate the text the user enters.
Always the way... I found it. It's not listed on the page for NSTextFieldDelegate, or NSControlTextEditingDelegate, but on the page for NSControl itself.
The delegate method is: -controlTextDidChange:.
I have a UIView with a bunch of buttons in it (something like 200 of them)...
The view was set up in IB so I would have to manually wire every button with a single handler...
I'm trying to traverse the subviews of the view, looking for buttons and then set the button's target programmatically... which results in a crash (I get the compile warning «UIButton may not respond to addTarget...»).
this is the loop:
for(UIButton *aButton in self.view.subviews){
if([aButton isKindOfClass:[UIButton class]]){
[aButton addTarget:self selector:#selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
}
}
I can access some of the properties of the button, like visibility and title... but not the action?
Any help greatly appreciated...!
wow - it was actually pretty simple - the guys over at devforums.apple.com gave me the hint...
for(UIButton *aButton in self.view.subviews){
if([aButton isKindOfClass:[UIButton class]]){
[aButton addTarget:self action:#selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
}
}
Can you spot the difference? ;)
You could use respondsTo or some other variant to avoid getting the error. This would ensure you can set the action for aButton.
However, if you are looping over all these buttons anyway, why not just build them programmatically? Are they design heavy?
you should mark your answer as correct.
But just in case anybody else comes:
It should be:
addTarget:self action:#selector(buttonClick:)
instead of:
addTarget:self selector:#selector(buttonClick:)