2011-02-23 75 views
1

我有一个文本框和两个按钮。用户应该能够在编辑完文本字段后按回车键,然后再次返回以激活其中一个按钮,具体取决于条件。为了让用户清楚他们可以返回来激活按钮,我暂时将返回值指定为所选按钮的等效值,这会使其变为蓝色。NSTextField两次捕获返回键事件

TextField的发送动作选择包括以下代码:

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焕发蓝色:

[self.btnSaveAndNext setKeyEquivalent:@""]; 

问题是,当用户退出文本字段时,返回键事件以某种方式被捕获两次,并且程序自己激活该按钮,即使用户还没有实际按下再次返回。

有没有一种方法可以完全捕获并处理第一个返回键事件,所以这不会发生?

+0

我发现这个问题也发生了 - 原来改变IB上的“发送操作”菜单项检查员调色板不起作用。我不得不手动调用'[self.searchTextField.cell setSendsActionOnEndEditing:NO]'来避免两次执行我的操作。 – nielsbot 2013-12-02 22:31:20

+0

谢谢。这可能是比我接受的答案更好的解决方案。 – Wienke 2013-12-24 19:27:11

回答

1

嗯,我有一个kludge。

我添加了一个boolean属性shouldSwallowThisReturn。我补充说,设置这个布尔值是在文本框的发送动作选择线路:

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

所以其余按钮的动作仅在用户第二次按下返回后执行。

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

苹果的事件处理指南进一步审查表明,什么是错的:显然,当你使用IB来分配一个发送的行动到一个文本字段,虽然当用户按下返回时,该动作被设置,该返回不会注册作为一个关键等价物,因此对应用程序的performKeyEquivalent查询没有回应,因此应用程序一直在寻找一个能够回答yes的控件,因此最终它会自行调用该按钮。

这样看来我真的应该做的是子类的文本框,并使其返回是,如果键代码为36(为返回键代码)重写其performKeyEquivalent方法,像这样:

- (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状态早已当已被转移到按钮。所以重写不起作用。

现在,我在这个答案的顶部卡住了kludge。但必须有一些方法来获得一个发送动作,以完全捕获返回键事件,将其设置为关闭...

+0

StackOverflow妖精建议我关闭这个问题。我将这个答案标记为已接受,因为事实上布尔应该使用SwallowThisReturn kludge,并且给了我很多控制权。 – Wienke 2011-03-25 15:46:40