NSTextField дважды захватывает событие возврата ключа - PullRequest
1 голос
/ 23 февраля 2011

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

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

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:@""];

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

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

1 Ответ

1 голос
/ 23 февраля 2011

Ну, у меня есть клудж.

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

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, этот возврат не регистрируется как ключевой эквивалент, и, следовательно, не отвечает да на запрос executeKeyEquivalent приложения, и поэтому приложение продолжает искать элемент управления, который ответит да, поэтому в конечном итоге он вызывает кнопку самостоятельно.

Похоже, что я действительно должен сделать, это создать подкласс текстового поля и переопределить его метод executeKeyEquivalent, чтобы он возвращал yes, если keyCode равен 36 (код для ключа возврата), например:

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

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

Я изменил метод переопределения, чтобы проверить идентичность 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;
}

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

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

...