0

I am having difficulties with setting a tab-order for my NSTextFields.

In my AppDelegate I add a NSViewController

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    CustomViewController *vc = [[CustomViewController alloc] init];
    [_window.contentView addSubview:vc.view];
    [_window setAutorecalculatesKeyViewLoop:NO];

    [_window.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:@{@"view":vc.view}]];
    [_window.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:@{@"view":vc.view}]];

}

Then in my NSViewController I add custom NSViews which contain a label and a text field.

- (void)viewDidLoad {

    _customView = [[CustomView alloc] initWithLabel:@"Foo"];
    [self.view addSubview_customView];

    _customView1 = [[CustomView alloc] initWithLabel:@"Bar"];
    [self.view addSubview_customView1];

        _customView2 = [[CustomView alloc] initWithLabel:@"FooBar"];
    [self.view addSubview_customView2];

}

And finally I have the CustomView which implements the label and text field as follows:

- (void)initWithLabel:(NSString *)label {

    self = [super initWithFrame:NSZeroRect];
    if (self) {

        _label = [[NSTextField alloc] initWithFrame:NSZeroRect];
        _label.stringValue = label;
        _label.font = [NSFont fontWithName:@"HelveticaNeue-Light" size:12.0f];
        _label.alignment = NSLeftTextAlignment;
        _label.textColor = [NSColor grayColor];
        _label.selectable = NO;
        _label.editable = NO;
        _label.drawsBackground = NO;
        _label.bezeled = NO;
        [self addSubview:_label];

        _textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
        _textField.stringValue = @"";
        _textField.alignment = NSRightTextAlignment;
        _textField.font = [NSFont fontWithName:@"HelveticaNeue-Light" size:32.0f];
        [self addSubview:_textField];

    }
    return self;
}

I do the positioning with NSLayoutConstraints and everything looks fine and works as expected, except when I try to implement setNextKeyView:.

I have tried to do it by using the exposed textField in the viewDidLoad of the view controller like:

... 
[_customView.textField setNextKeyView:_customView1.textField];
[_customView1.textField setNextKeyView:_customView3.textField];
[_customView2.textField setNextKeyView:_customView.textField];
...

But that did not work. When pressing tab-key from a NSTextField the current field loses focus, but the next one does not gain it. I also tried calling [[[self view] window] recalculateKeyViewLoop] afterwards but that didn't help either.

How do I go about doing this? I also played around with setting NSWindow setAutorecalculatesKeyViewLoop: to YES but that also did not haven an effect.

Thanks

PS: this is pseudo-code to simplify things. If a brace is missing or there is a typo, then that is not my problem. It compiles fine and works too. Just the tabbing is not behaving as expected. ;-)

Joseph
  • 9,171
  • 8
  • 41
  • 67
  • If you press Tab some more, does focus eventually get to the other text fields? Also, you should use `-initWithFrame:` to initialize the superclass and the `NSTextField`s. I realize you're using auto layout, so the frame will be overridden, but it's still the designated initializer. You can pass `NSZeroRect`. – Ken Thomases Dec 15 '14 at 19:46
  • No it never gets to the other fields. I changed the init to NSZeroRect. – Joseph Dec 16 '14 at 07:35
  • You didn't change it for the call to `[super init]`, at least not in your edited code. – Ken Thomases Dec 16 '14 at 07:59
  • What methods are you overriding in your `CustomView`? Are you using a custom field editor? If so, how is that set up? – Ken Thomases Dec 16 '14 at 08:05
  • it is a subclass of `NSView` and there are no methods that are being overridden. – Joseph Dec 16 '14 at 09:03

1 Answers1

0

As @Ken mentioned in his comment try like this:-

if ([_customView1.textField acceptsFirstResponder]) 
{
 [_customView1.window makeFirstResponder:_customView1.textField]
}
Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
  • You should not call either `-resignFirstResponder` or `-becomeFirstResponder` (except to call through to `super` in an override). This is documented for both methods. You could do `if ([_customView1.textField acceptsFirstResponder]) [_customView1.window makeFirstResponder:_customView1.textField];`, but you shouldn't have to replace/re-implement the key loop functionality. Also, returning `YES` unconditionally from this method will break all other command selectors for the text fields. – Ken Thomases Dec 15 '14 at 19:33
  • No, this doesn't work. If focuses the first view, but the cursor is not blinking in the text field. Tabbing has no effect, except that the first field loses focus. – Joseph Dec 16 '14 at 07:35
  • resign the responder to the first view and then try – Hussain Shabbir Dec 16 '14 at 07:47
  • @dave, that's UIKit, not Cocoa. See [here](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/index.html#//apple_ref/occ/instm/NSResponder/becomeFirstResponder): "Never invoke this method directly." – Ken Thomases Dec 16 '14 at 07:56
  • @HussainShabbir do you mean to put `[_customView1 resignFirstResponder]` before of the if statement? – Joseph Dec 16 '14 at 08:01
  • @KenThomases My mistake; after so many years the Cocoa / UIKit prefixes have all but disappeared to me. – dave Dec 16 '14 at 13:35
  • Have redesigned the class structure. Am now no longer wrapping a `NSTextField` in an `NSView` instead I subclassed `NSTextField`. The tabbing issue is solved, but a different issue has arisen. http://stackoverflow.com/questions/27579756/adding-non-editable-nstextfield-as-a-label-into-another-nstextfield – Joseph Dec 20 '14 at 11:37