NSTextField дважды фиксирует событие возврата ключа

У меня есть текстовое поле и две кнопки. После завершения редактирования текстового поля пользователь должен иметь возможность нажать клавишу возврата, а затем вернуться снова, чтобы активировать ту или иную кнопку, в зависимости от условий. Чтобы дать пользователю понять, что он может вернуться, чтобы активировать кнопку, я временно назначаю return в качестве эквивалента клавиши выбранной кнопки, в результате чего она должна светиться синим цветом.

Селектор отправленного действия текстового поля включает следующий код:

switch (self.iNavMode) {
    case kNavModeNeutral:
        break;
    case kNavModeSaveAndNew:
        [self.window makeFirstResponder:self.btnSaveAndNew];
        [self.btnSaveAndNew setKeyEquivalent:@"\r"];
        break;
    case kNavModeSaveAndNext:
        [self.window makeFirstResponder:self.btnSaveAndNext];
        [self.btnSaveAndNext setKeyEquivalent:@"\r"];
        break;
    default:
        break;
}

Действие выбранной кнопки затем выбивает ее эквивалент, так что кнопка не будет продолжать светиться синим после того, как она уйдет в отставку первым Ответ:

[self.btnSaveAndNext setKeyEquivalent:@""];

Проблема в том, что когда пользователь возвращается из текстового поля, событие клавиши возврата каким-то образом фиксируется дважды, и программа активирует кнопку сама по себе, даже если пользователь на самом деле еще не нажал клавишу возврата.

Есть ли способ полностью захватить и удалить первое событие клавиши возврата, чтобы этого не произошло?


person Wienke    schedule 23.02.2011    source источник
comment
Я тоже обнаружил проблему с этим - оказывается, изменение действия отправки в пункте меню в палитре инспектора IB не имеет никакого эффекта. Мне пришлось вручную вызвать [self.searchTextField.cell setSendsActionOnEndEditing:NO], чтобы дважды не получить свое действие.   -  person nielsbot    schedule 03.12.2013
comment
Спасибо. Это могло быть лучшим решением, чем моя кладжа принятых ответов.   -  person Wienke    schedule 24.12.2013


Ответы (1)


Что ж, у меня есть кладж.

Я добавил логическое свойство shouldSwallowThisReturn. И я добавил строку, которая устанавливает для этого логического значения yes в селекторе отправленных действий текстового поля:

switch (self.iNavMode) {
    case kNavModeNeutral:
        break;
    case kNavModeSaveAndNew:
        [self.window makeFirstResponder:self.btnSaveAndNew];
        self.shouldSwallowThisReturn = YES;
        [self.btnSaveAndNew setKeyEquivalent:@"\r"];
        break;
    case kNavModeSaveAndNext:
        [self.window makeFirstResponder:self.btnSaveAndNext];
        self.shouldSwallowThisReturn = YES;
        [self.btnSaveAndNext setKeyEquivalent:@"\r"];
        break;
    default:
        break;
}

И я добавил к действию выбранной кнопки несколько строк:

if (self.shouldSwallowThisReturn) {
    self.shouldSwallowThisReturn = NO;
    return;
}
[self.btnSaveAndNext setKeyEquivalent:@""];

Таким образом, остальная часть действия кнопки выполняется только после того, как пользователь нажмет клавишу возврата во второй раз.

Это работает, но я бы предпочел более элегантное решение.

Дальнейшее изучение руководства Apple по обработке событий показывает, что не так: по-видимому, когда вы используете IB для назначения отправленного действия текстовому полю, хотя действие отключается, когда пользователь нажимает return, это return не регистрируется как эквивалент ключа. , и поэтому не отвечает «да» на запрос performKeyEquivalent приложения, и поэтому приложение продолжает искать элемент управления, который отвечает «да», поэтому в итоге оно вызывает кнопку самостоятельно.

Итак, кажется, что мне действительно нужно создать подкласс текстового поля и переопределить его метод performKeyEquivalent, чтобы он возвращал yes, если keyCode равен 36 (код для клавиши возврата), например:

- (BOOL) performKeyEquivalent:(NSEvent *)theEvent {
    printf("\nThe keycode is %d", [theEvent keyCode]);
    if ([theEvent keyCode] == 36) 
        return YES;
    else 
        return NO;
}

Но происходит то, что метод переопределения вызывается, даже если целевое текстовое поле не имеет фокуса. Действительно, он вызывается, даже когда выбранная кнопка уже является firstResponder. Итак, теперь возврат пользователя всегда прерывается, а действие кнопки никогда не вызывается.

Я изменил метод переопределения, чтобы проверить личность firstResponder:

- (BOOL) performKeyEquivalent:(NSEvent *)theEvent {
    printf("\nThe keycode is %d", [theEvent keyCode]);
    if ([theEvent keyCode] == 36) {
        ThisProject_AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
        id firstResponder = [appDelegate.windowController.window firstResponder];
        if ([firstResponder isKindOfClass:[NSTextView class]]) {
            printf("\nfirstResp is a field editor, a textview.");
            if ([firstResponder delegate] == self) {
                printf("\ntarget textfield is firstResponder.");
                return YES;
            }
        }
        else if ([firstResponder isKindOfClass:[NSButton class]]) {
            printf("\nfirstResp is a button.");
            return YES;
        }
    }
    return NO;
}

Оказывается, переопределение вызывается после выполнения действия send-action текстового поля, когда статус firstResponder уже был передан кнопке. Так что переопределение не помогает.

На данный момент я застрял с клуджем в верхней части этого ответа. Но должен быть какой-то способ получить отправленное действие, чтобы полностью захватить событие клавиши возврата, которое его вызвало ...

person Wienke    schedule 23.02.2011
comment
Лепреконы StackOverflow предлагают закрыть этот вопрос. Я отмечаю этот ответ как принятый, потому что на самом деле кладж BOOL shouldSwallowThisReturn работал хорошо и давал мне большой контроль. - person Wienke; 25.03.2011