NSTextField 两次捕获返回键事件 [英] NSTextField captures return key event twice

查看:117
本文介绍了NSTextField 两次捕获返回键事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文本框和两个按钮.用户应该能够在编辑完文本字段后按回车键,然后再次返回以激活一个或另一个按钮,具体取决于条件.为了让用户清楚他们可以返回来激活按钮,我暂时将返回指定为所选按钮的等效键,这应该使它发出蓝色光.

I have a textfield and two buttons. The user should be able to press return when they’re done editing the textfield, and then return again to activate one or the other of the buttons, depending on conditions. In order to make it clear to the user that they can return to activate the button, I temporarily assign return as the chosen button’s key equivalent, which should make it glow blue.

文本字段的发送操作选择器包含以下代码:

The textfield’s sent-action selector includes this code:

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;
}

所选按钮的操作然后取消等效键,这样按钮在退出 firstResponder 后就不会继续发出蓝色光:

The chosen button’s action then knocks out the key equivalent, so that the button won’t continue to glow blue once it resigns firstResponder:

[self.btnSaveAndNext setKeyEquivalent:@""];

问题在于,当用户从文本字段中返回时,返回键事件会以某种方式被捕获两次,并且程序会自行激活按钮,即使用户实际上并没有再次按下返回键.

The problem is that when the user returns out of the textfield, the return key event is somehow captured twice, and the program activates the button on its own, even though the user has not actually pressed return again.

有没有办法可以完全捕获并处理第一个返回键事件,以免发生这种情况?

Is there a way that I can completely capture and dispose of the first return key event so this doesn’t happen?

推荐答案

好吧,我有一个问题.

我添加了一个布尔属性 shouldSwallowThisReturn.我在文本字段的发送操作选择器中添加了一行,将此布尔值设置为 yes:

I added a boolean property shouldSwallowThisReturn. And I added a line that sets this boolean to yes in the textfield’s sent-action selector:

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;
}

我在所选按钮的操作中添加了几行:

And I added a few lines to the chosen button’s action:

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

所以按钮的其余动作只有在用户第二次按下返回键后才会执行.

So the rest of the button’s action executes only after the user has pressed return a second time.

这可行,但我更喜欢更优雅的解决方案.

This works, but I would prefer a more elegant solution.

对 Apple 的事件处理指南的进一步检查表明出了什么问题:显然,当您使用 IB 将发送的操作分配给文本字段时,尽管该操作在用户按下回车键时被触发,但该回车并未注册为一个等效键,因此不会对应用的 performKeyEquivalent 查询响应 yes,因此应用一直在寻找响应 yes 的控件,因此它最终会自行调用按钮.

Further examination of Apple’s event-handling guide suggests what’s wrong: Apparently, when you use IB to assign a sent-action to a textfield, although the action is set off when the user presses return, that return doesn’t register as a key equivalent, and therefore doesn’t respond yes to the app’s performKeyEquivalent query, and therefore the app keeps looking for a control that will respond yes, so it ends up calling the button on its own.

所以看起来我真正应该做的是子类化文本字段并覆盖它的 performKeyEquivalent 方法,以便它在 keyCode 为 36(返回键的代码)时返回 yes,如下所示:

So it seems what I really should do is subclass the textfield and override its performKeyEquivalent method so that it returns yes if the keyCode is 36 (the code for the return key), like this:

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

但是,即使目标文本字段没有焦点,也会调用 override 方法.事实上,即使选择的按钮已经是 firstResponder,它也会被调用.所以现在用户的返回总是被抢占,按钮的动作永远不会被调用.

But what happens is that the override method is called even when the target textfield does not have focus. Indeed, it gets called even when the chosen button is already firstResponder. So now the user’s return is always preempted and the button’s action is never called.

我修改了override方法来检查firstResponder的身份:

I revised the override method to check the identity of the 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 状态已经转移到按钮时,在执行文本字段的发送操作后调用覆盖.所以覆盖没有帮助.

It turns out that the override is called after the execution of the textfield’s sent-action, when the firstResponder status has already been transferred to the button. So the override doesn't help.

现在,我被困在这个答案顶部的杂乱无章.但是必须有某种方法来获取发送操作以完全捕获将其设置为关闭的返回键事件......

For now, I’m stuck with the kludge at the top of this answer. But there must be some way to get a sent-action to fully capture the return key event that set it off…

这篇关于NSTextField 两次捕获返回键事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆