Проблемы с настройкой FirstResponder в Cocoa Mac OSX

Я работаю над крошечным приложением только для того, чтобы изучить какао, и мне трудно настроить FirstResponder для некоторых NSTextFields.

Когда представление открывается, я хочу, чтобы был выбран первый NSTextField, clientNumber, поэтому я запускаю [clientNumber beFirstResponder] в конце моего метода loadView, но он не выбирает текстовое поле. Но когда я нажимаю кнопку, запускающую метод (IBAction)addToArray, он выбирает правильное текстовое поле. Кроме того, у меня есть еще одно текстовое поле, оно должно содержать только целые числа, поэтому у меня есть грубая проверка для него. Когда содержимое не является целым, я получаю звуковой сигнал, как и должно быть, но не выбирает текстовое поле.

Вот мой код:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
      NSLog(@"initWithNibName");
    }
    return self;
}

- (void)viewWillLoad {
    NSLog(@"viewWillLoad");
}

- (void)viewDidLoad {
    NSLog(@"viewDidLoad");
    [self initNewInvoice];    
}

- (void)loadView {
    NSLog(@"loadView");
    [self viewWillLoad];
    [super loadView];
    [self viewDidLoad];
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.clientNumber]; 
}

- (void)awakeFromNib
{
    NSLog(@"awakeFromNib");
}

- (IBAction)saveInvoice:(id)sender
{
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.invoiceCredit]; 
}

- (IBAction)addToArray:(id)sender
{
    [clientNumber setStringValue: @"Toodeloo"];
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.clientNumber];  
}

- (IBAction)updateCreditDays:(id)sender
{
    if(invoiceCredit.intValue){
        [self updateCredit];
    }else{
        NSBeep();
        FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.invoiceCredit]; 
    }
}

Я действительно надеюсь, что кто-то может помочь мне здесь.

РЕДАКТИРОВАТЬ:

Я все понял неправильно, спасибо за подсказки, но когда я исправляю код, используя это: FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; [appDelegate.window makeFirstResponder:self.invoiceCredit]; вместо того, чтобы стать первым ответчиком. Но это все еще не работает.


person GJ Nilsen    schedule 31.08.2011    source источник


Ответы (5)


Вы делаете это намного сложнее, чем это должно быть.

В Interface Builder установите выход initialFirstResponder вашего окна так, чтобы он указывал на ваше текстовое поле.

Вот и все.

Если вам абсолютно необходимо сделать это программно, используйте:

[window setInitialFirstResponder:yourTextField];

Помните, что если вы боретесь с Cocoa за то, что кажется простым, то вы, вероятно, делаете это неправильно.

person Rob Keniger    schedule 31.08.2011
comment
Текстовое поле не загружается при первом открытии окна. Существует пять различных представлений, которые загружаются в зависимости от того, какую кнопку пользователь нажимает в окне. Вот почему я должен установить фокус на соответствующее текстовое поле позже. - person GJ Nilsen; 01.09.2011
comment
Не работает с такими вещами, как SplitViewControllers. Установите его программно в viewDidAppear - person Duncan Groenewald; 25.07.2018

Переопределите viewDidAppear и в указанном методе вызовите метод NSTextField's beFirstResponder.

Обратите внимание, что в моей собственной работе viewWillAppear оказалось слишком ранним для указанного вызова, независимо от того, использовался ли метод NSTextField's 's gotFirstResponder или метод NSWindow's makeFirstResponder.

person Jason McClinsey    schedule 27.11.2017

Проблема в том, что self.view.window имеет значение null в методе viewDidLoad контроллера первого представления до тех пор, пока не завершится выход applicationDidFinishLaunching. Таким образом, функция beFirstResponder не работает в режиме viewDidLoad. Попробуйте отложить настройку первого ответчика, например:

[_yourTextField PerformSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.1];

person Jeff    schedule 24.12.2016

Вы никогда не должны пытаться установить первого ответчика в методе viewDidLoad, потому что window в этот момент все еще равен нулю. Вместо этого используйте viewWillAppear:

- (void)viewWillAppear
{
    [super viewWillAppear];
    if (!_started) {
        _started = YES;
        [self.view.window makeFirstResponder:_yourView];
    }
}

Apple также однажды сказала, что вам никогда не следует напрямую вызывать функцию beFirstResponder. Вместо этого используйте [yourWindow makeFirstResponder:yourView];.

person Borzh    schedule 10.05.2017
comment
Вы правы.. Эту тему давно надо было закрыть, вопрос был актуален 6 лет назад, когда он был размещен. Сейчас API другие, и в любом случае это был бы неправильный подход. ;) - person GJ Nilsen; 11.05.2017
comment
Я просто добавил этот ответ, чтобы помочь другим парням с проблемами какао. - person Borzh; 11.05.2017

Просто прочитайте документацию:

стать первым ответчиком

Уведомляет получателя о том, что он собирается стать первым ответчиком в своем NSWindow.

[...]

Используйте метод NSWindow makeFirstResponder:, а не этот метод, чтобы сделать объект первым ответчиком. Никогда не вызывайте этот метод напрямую.

person Nikolai Ruhe    schedule 31.08.2011
comment
Спасибо, я попытался использовать: FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication]делегат]; [appDelegate.window makeFirstResponder:self.invoiceCredit]; вместо beFirstResponder, и это все равно не работает. - person GJ Nilsen; 01.09.2011
comment
Это спасло мой день, +1 - person Tom Vos; 05.03.2020