I have a Core Data project.
Basically I have an NSTableView where I add some entities (using the "add:" selector), double clicking on the TableView opens a new NSWindow where is possible to edit the entity using some NSTextFields.
Each text field is binded to an attribute of the entity.
Everything is working fine, except the fact that the entity's attributes are updated only when a textfield lose the focus.
If I write on the first text field and then I move to the second one my entry is saved, but if I write on the first text field and I close the window I lose my changes.
How can I update my core data entity as soon as I write something in the text field? Should I use textDidChange:?
--- UPDATE ---
Unfortunately [context save] doesn't work. If I understand correctly the entity is not modified until the NSTextField resign first responder.
The only working solution for now is something like:
(void)controlTextDidChange:(NSNotification *)aNotification
{
NSTextField *tf = [aNotification object];
[self.window makeFirstResponder:tf];
}
but this is quite inelegant, and in any case I also still need to re-set the cursor at the end of the NSTextField.
Setting NSContinuouslyUpdatesValueBindingOption will cause the model to update every time the text field changes, which sets the dirty flag properly and causes the document to save on quit.
I think you could use DidEndEditing or TextDidChange, another way of doing this is handeling in the window close event, but I would not recommend it.
If you don't have one already, you can set a delegate on the window and use -windowWillClose: or observe the NSWindowWillCloseNotification. You can then call [[notification object] makeFirstResponder:[window initialFirstResponder]] to set the window's first responder to its initial first responder as the window is closing. This will cause the control that is first responder (e.g. NSTextField) to resign the first responder status and the binding will save the changes.
Related
I'm trying to remove focus from a UITextField and even though I resign it from being first responder, I'm still not able to have the cursor not focus on the text field.
I don't have any other input on the view to move the focus to and I don't want to create a dummy one either. What is a good workaround for this?
As per the documentation.
To dismiss the keyboard, send the resignFirstResponder message to the text field that is currently the first responder. Doing so causes the text field object to end the current editing session (with the delegate object’s consent) and hide the keyboard.
If you call resignFirstResponder on your textfield then it will end the editing session and the cursor wont be focussing on that textfield.
So please verify one more time whether resignFirstResponder is getting called on that textfield which you want to remove the focus.
Please try to set your current class as delegate of your UITextField. I think you forget to set the delegate that's why it's not working as you are expecting.
I'm trying to detect when user finishes editing a NSTextField by implementing NSTextFieldDelegate's controlTextDidEndEditing: method. However the problem is that upon initially making the NSTextField first responder of the window, immediately the controlTextDidEndEditing: notification gets fired. I tried this in an extremely simple test app and confirms the result. Would really appreciate some pointers on why this is the case and how to detect when textField loses focus.
As the text field is first Responder, selectText: message will also sent to textField, which will cause it to end editing. If you don't want this behavior set NO to selectable property of textField.
- (void)selectText:(id)sender;
Ends editing and selects the entire contents of the receiver if it’s selectable.
I'm working on an app that presents an NSPopover containing a number of NSTextFields. While I can tab between these fields as I expect, the popover is selecting a particular text field to be in the editing state when it appears, and it's not the field I want to edit; I'd like to be able to define which text field is editing on popover appearance programmatically (or in Interface Builder). How can I do this?
I've set up the appropriate key view loop by connecting IB outlets for all the various text fields involved, and I've hooked up the popover's nextResponder property to the text field I want to edit first, but that doesn't seem to have an effect - the popover will still select its preferred text field instead of mine. The Window Programming Guide suggests that I set the initialFirstResponder outlet of the window to the view I want selected, but an NSPopover is not an NSWindow and has no initialFirstResponder property (unless I'm missing something obvious).
Is there any way to specify which NSTextField I want to be editing when an NSPopover appears?
I think you said you tried using -makeFirstResponder: and passing the text field. This will set the window's firstResponder, but that's not the same as initialFirstResponder and the window must have initialFirstResponder set to something other than nil in order to respect the key view loop. (Source) A slight tweak to what you tried worked for me:
- (void)popoverWillShow:(NSNotification *)notification
{
// Set the window's initialFirstResponder so that the key view loop isn't auto-recalculated.
[[myField window] setInitialFirstResponder:myField];
}
I think you can make this work by setting all the text field's that you don't want to have focus to "selectable" instead of "Editable" in IB, this should leave the one text field you want to start with as the first responder. Then, in your popoverDidShow: method, set them all back to editable, and you should be able to tab between them as usual.
I have several panels that contain NSTextField controls bound to properties within the File's Owner object. If the user edits a field and then presses Tab, to move to the next field, it works as expected. However if the user doesn't press Tab and just presses the OK button, the new value is not set in the File's Owner object.
In order to workaround this I have set Updates Continuously in the binding, but this must be expensive (EDIT: or at least it's inelegant).
Is there a way to force the bind update when the OK button is pressed rather than using Updates Continuously?
You're right that you don't need to use the continuously updates value option.
If you're using bindings (which you are), then what you should be doing is calling the -commitEditing method of the NSController subclass that's managing the binding. You'd normally do this in your method that closes the sheet that you're displaying.
-commitEditing tells the controller to finish editing in the active control and commit the current edits to the bound object.
It's a good idea to call this whenever you are performing a persistence operation such as a save.
The solution to this is to 'end editing' in the action method that gets called by the OK button. As the pane is a subclass of NSWindowController, the NSWindow is easily accessible, however in your code you might have to get the NSWindow via a control you have bound to the controller; for example NSWindow *window = [_someControl window].
Below is the implementation of my okPressed action method.
In summary I believe this is a better solution to setting Updated Continuously in the bound controls.
- (IBAction)okPressed:(id)sender
{
NSWindow *window = [self window];
BOOL editingEnded = [window makeFirstResponder:window];
if (!editingEnded)
{
logwrn(#"Unable to end editing");
return;
}
if (_delegateRespondsToEditComplete)
{
[_delegate detailsEditComplete:&_mydetails];
}
}
Although this is really old, I absolutely disagree with the assumption that this question is based on.
Countinously updating the binding is absolutely not expensive. I guess you might think this updates the value continuously, understanding as "regularly based on some interval".
But this is not true. This just means it updates whenever you change the bound value. This means, when you type something in a textView, it would update as you write; this is what you'd want in this situation.
I have implemented a NSTokenField which uses some custom data objects for display of dynamic data. Delegate is set up fine and displays the correct values of the token.
I've also implemented a menu on the tokens which allows selection of the format used for display of each token. My problem is however that I'm unable to make the NSTokenField respond immediately to these changes and redraw the token with the newly selected format.
If I click outside of the NSTokenField so it resigns first responder it redraws immediately. I can also do this programmatically by explicitly setting first responder to nil. The only problem with this is that the NSTokenField looses focus - and reassigning it as first responder selects everything in the field so the user may accidentally overwrite the entire content.
So my question is whether there are any way of just triggering the NSTokenField to redraw its content without changing focus and selection?
I had the same problem and found the only workable solution was to "reset" the token field every time its contents changed. Basically this boiled down to running the following method of the view controller that handled the view with the token field:
- (void) resetTokenField {
// Force the token field to redraw itself by resetting the represented object.
id anObject = [self representedObject];
[self setRepresentedObject: nil];
[self setRepresentedObject: anObject];
[[self tokenField] setNeedsDisplay: YES];
}
The represented object is the object that holds all the tokens that are being displayed. In my case that was a chunk of richt text where tokens are basically tags.
I found NSTokenField to be a royal pain in the neck but persevered as I quite like the presentation side of it.
EDIT: My token field was bound to the tagsAsArray method of the represented object of the view controller. So basically I used Cocoa bindings to solve the problem.
It turns out that you are supposed to call setNeedsDisplay on the NSTextView object used by the NSTokenField, instead of calling setNeedsDisplay on the NSTokenField itself.
Thus the following code works: (Written in PyObjC)
text_view = token_field.cell().fieldEditorForView_(token_field)
text_view.setNeedsDisplay_(YES)