NSTextFieldCell Delegate? - objective-c

I have a text field cell in a table view, from which I need to be made aware when it ends editing. I thought I would set my Controller class as the text field cell's delegate, and then use NSTextField's delegate method textDidEndEditing:, but realized that the text field cell doesn't seem to have delegate methods? Why is this, and what can I do (other than subclassing) to be informed when editing is finished?
Thanks

NSTextFieldCell inherits from NSCell (well, technically from NSActionCell which inherits from NSCell). The NSCell class is used to (from the docs):
The NSCell class provides a mechanism for displaying text or images in an NSView object without the overhead of a full NSView subclass.
Notably, The cell class is used for "displaying text or images", and not dealing with interaction with the user. Similarly, with the NSTextField class:
The NSTextField class uses the NSTextFieldCell class to implement its user interface.
The NSTextField deals with the actual user input, whilst using the text field cell to simply implement its user interface, and similarly, the delegate methods to provide notification when the editing of text has ended is provided through the NSTextField class and not through the NSTextFieldCell class.
If you want to be notified of when editing ends in an NSTableView, then you need to register yourself as an observer of the NSTextDidEndEditingNotification (you might want to read the NSNotificationCenter class reference if you are unfamiliar with notifications). To do this, place the following in your controller class; the awakeFromNib function is a good place to include it to ensure that it is called upon your application's startup:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(textDidEndEditing:)
name:NSTextDidEndEditingNotification
object:tableView];
Where tableView is the pointer to your NSTableView object. Then, simply implement the method as follows:
- (void)textDidEndEditing:(NSNotification *)aNotification
{
// Do what you want here
}
Don't forget to remove yourself as an observer upon deallocation:
- (void)dealloc
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
}
The reason that you set the object that you are observing to be the NSTableView instance (and not the cell itself) is that under the hood, when you edit a cell in the table, the cell that you are dealing with isn't being edited directly; it is the window's (or a custom) field editor. When editing ends, the field editor then passes the new value for that cell on to the table view. However the table view will post a notification to say that a cell has finished being edited.

Implement the tableView:setObjectValue:forTableColumn:row: method in the NSTableViewDataSource protocol. Put it next to the tableView:objectValueForTableColumn:row: method that you've already implemented.
- (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(NSInteger)rowIndex
{
[mutableArrayWithStrings replaceObjectAtIndex:rowIndex withObject:anObject];
}

Related

Click textfield and button disappears (it doesn't, but i want it to)

I have a textfield and a button. When I click inside the textfield, I want the button to disappear. I defined the textfield as both outlet and action ( with event “Did end on exit”). In the method for the textfield, I have self.testButton.hidden = YES; When I click inside the textfield, the button does not go away. Instead, it remains until I hit the return key on the keyboard – causing the keyboard to go away. I tried the same thing w/ touchup inside as the event on the text field. When you click in the text field, nothing happens to the button.
Instead of using the Target-Action mechanism ("Did end on exit" and "Touch Up Inside") use the Delegate mechanism.
First, make your class conform to the UITextFieldDelegate protocol. In your *.h (header) file add the following:
// Here I'm assuming your class is inheriting from UIViewcontroller but it
// may be inheriting from some other class. The really important part here
// is: <UITextFieldDelegate>. That's how you make your class conform to that protocol
#interface THE_NAME_OF_YOUR_CLASS : UIViewController <UITextFieldDelegate>
.
Second, implement the -(void)textFieldDidBeginEditing:(UITextField *)textField method. Also, remember to set yourself as the delegate too: self.textField.delegate = self. That way, the method will get called every time the user starts editing. Inside that methdod call self.testButton.hidden = YES;. In your *.m (implementation) file add the following:
-(void)viewDidLoad {
// here I'm assuming you have a 'strong' reference to your text field.
// You're going to need one to set yourself as the delegate.
self.textField.delegate = self;
}
// This is one of the methods defined in the UITextFieldDelegate protocol
-(void)textFieldDidBeginEditing:(UITextField *)textField {
self.testButton.hidden = YES;
}
.
Similarly, to make your button appear again, implement the - (void)textFieldDidEndEditing:(UITextField *)textField method. Inside it un-hide your button. Again, in your *.m file add the following:
// This is another method defined in the UITextFieldDelegate protocol
-(void)textFieldDidEndEditing:(UITextField *)textField {
self.testButton.hidden = NO;
}
Although delegates may be a mystery to you right now once you become familiar with them
you will realize they're very easy. And this is very important because iOS programming
relies heavily on delegates.
A delegate is a "notification" mechanism based on the "Hollywood" principle which is: don't call us; we'll call you.
In your case the class that contains the UITextField is interested in knowing when the UITextField begins editing and when it ends editing. But your class cannot be "polling" (that is, constantly asking) the text field to find out if the state changed. Instead you register your class with the text field and it will be the text field the one that will let you know when something happened. That will be thanks to the methods that you implemented.
Further reading: protocols and delegates
Hope this helps!
Have you made sure that testButton has its IBOutlet set before you hide it?
If you want to button to disappear when the user begins editing the text field, try UIControlEventEditingDidBegin.

textDidChange not called ( NSTextFieldDelegate )

Step 1. Add a NSTextField in xib
Step 2. Add NSTextFieldDelegate in .h file,Control-drag NSTextField to File's Owner to set delegate to it
Step 3, In .m file add the method:
- (void)textDidChange:(NSNotification *)notification{
NSLog(#"textDidChange");
}
but the method textDidChange: not called?
Is any mistake?
The file's owner isn't the app delegate -- is the app delegate where you put that method? You should control drag to the blue cube labeled app delegate.
After Edit: The message that the delegate receives is controlTextDidChange: not textDidChange, so implement that one instead.
You need to register an observer to listen for the NSNotification.
// When the NSWindow is displayed, register the observer.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(controlTextDidChange:) name:NSControlTextDidChangeNotification object:nil];
- (void)controlTextDidChange:(NSNotification *)obj {
// You can get the NSTextField, which is calling the method, through the userInfo dictionary.
NSTextField *textField = [[obj userInfo] valueForKey:#"NSFieldEditor"];
}
It seems, the object returned by NSFieldEditor is a NSTextView, instead of the same NSTextField object, which you may expect.
However, according to Apples documentation, if you implement this method and the controls delegate is registered to this object, the notification shall be automatically registered.
The control posts a NSControlTextDidChangeNotification notification, and if the control’s delegate implements this method, it is automatically registered to receive the notification
Source: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSControl_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/controlTextDidChange:

Overriding keyDown: in an NSTableView category disables arrow key handling

I have an NSTableView and I have some issues with its default behavior.
If I've overridden the keyDown: method in a category as follows:
- (void) keyDown:(NSEvent *)event {
[super keyDown:event];
}
I can't change the row selection with the keyboard arrow keys anymore. Why is that?
in a category of NSTableView.
In a category of NSTableView, super refers to NSTableView's superclass (NSControl), not to NSTableView as it would in a subclass. You're passing the event on to the NSControl version of keyDown:, which knows nothing about table views and can't handle the arrow keys the way you want.
If you override a method in a category, there's no way to call the original method. It's almost never a good idea to do this on framework classes (whose source is unavailable to you). Use a subclass.
Cf. Using Super in an Objective C Category? and Is calling super in a category the same as calling it in a subclass?

Listen to a value change of my text field

I'm trying to understand how to catch a "text changed" event from a text field in my window. I'm used to Java's "action listeners", and can't find anything similar in Objective-C/Cocoa.
I searched for quite a while and found the "key value observing" protocol, but the observeValueForKeyPath: method (function?) only triggers when the value of my text field was changed in code (using [textfield setStringValue:...], e.g.), not by typing in it.
How can I "listen" to the value change when a user types in the text field?
You can set a delegate for your NSTextField instance and have the delegate implement the following method:
- (void)controlTextDidChange:(NSNotification *)notification {
// there was a text change in some control
}
Your delegate object can be the application delegate, a window controller, a view controller, or some other object in your application. The delegate can be programatically set via
[myTextField setDelegate:delegateObject];
or, in Interface Builder, via the delegate outlet available in the NSTextField control.
Note that if there are multiple controls hooked to the same delegate then -controlTextDidChange: will be sent for each control, i.e., the same method is called for different controls. If you want different behaviour according to the control where the text has changed, you can use -[NSNotification object] to identify the control that has sent the notification.
For instance, if you have two text fields with corresponding outlets nameField and addressField, and you’ve set the same delegate for both fields, then:
- (void)controlTextDidChange:(NSNotification *)notification {
// there was a text change in some control
// [notification object] points to the control that has sent
// the notification
if ([notification object] == nameField) {
// nameField has changed
}
else if ([notification object] == addressField) {
// addressField has changed
}
}
Alternatively, you could have one delegate for each text field. In this case, there’d be no need to test [notification object].
You can also just hook up to the "Editing Changed" from IB and create the Action to handle it
- (IBAction)txtField_Changed:(id)sender
{
// my textfield has been changed
}
This works for me
func textView(textView: NSTextView, shouldChangeTextInRange affectedCharRange: NSRange, replacementString: String?) -> Bool {
print("Changed!")
return true
}
You can use textFieldShouldBeginEditing: method of UITextFieldDelegate. In iOS listeners are called NSNotifications
EDIT
In objective-c a lot of UIObjects have a corresponding protocol class that's called "delegate" The delegate is responsible for reacting to events. So to be able to respond or to be notified about actions you need to implement the delegate and its methods.

Delegate methods of NSTextField using NSNotification

I have an NSTokenField in a window. I am using it to store tags related to a Core Data object. Right now I have it set up such that I can add tags to the objects, but I cannot delete them. I need a delegate method on the NSTokenField that can let me know when the user has moved the focus out of the NSTokenField. Since NSTokenField is a subclass of NSTextField I figured that I could use its delegate methods. It has two that I think could be useful:
- (void)textDidChange:(NSNotification *)aNotification
- (void)textDidEndEditing:(NSNotification *)aNotification
I set my controller class as the delegate of my NSTokenField and put both of these methods into my controller class. I put a basic NSLog into each of them and neither is triggered when I interact with the NSTokenField. I am guessing it has something to do with NSNotification. How do I activate these methods?
The NSTokenField invokes the controlTextDidChange: and the controlTextDidEndEditing: notifications; change the two methods above, implementing them as:
- (void)controlTextDidChange:(NSNotification*)aNotification
{
//Code here..
}
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
//Code here..
}