Objective c NSTextField捕获返回键事件两次
我有一个文本字段和两个按钮。用户应该能够在编辑完文本字段后按return键,然后根据条件再次按return键激活其中一个按钮。为了让用户清楚地知道,他们可以返回来激活按钮,我临时将return指定为所选按钮的等效键,这将使它发出蓝色的光芒 textfield的已发送操作选择器包含以下代码:Objective c NSTextField捕获返回键事件两次,objective-c,nstextfield,keyboard-navigation,Objective C,Nstextfield,Keyboard Navigation,我有一个文本字段和两个按钮。用户应该能够在编辑完文本字段后按return键,然后根据条件再次按return键激活其中一个按钮。为了让用户清楚地知道,他们可以返回来激活按钮,我临时将return指定为所选按钮的等效键,这将使它发出蓝色的光芒 textfield的已发送操作选择器包含以下代码: switch (self.iNavMode) { case kNavModeNeutral: break; case kNavModeSaveAndNew: [
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:@""];
- (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;
}
问题是,当用户从文本字段返回时,返回键事件不知何故被捕获两次,并且程序自己激活按钮,即使用户实际上没有再次按下返回键
有没有一种方法可以完全捕获并处理第一个返回键事件,这样就不会发生这种情况?嗯,我有一个难题 我添加了一个布尔属性shouldThisReturn。我在textfield的sent action选择器中添加了一行,将该布尔值设置为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:@""];
因此,按钮的其余操作仅在用户第二次按下return键后执行
这是可行的,但我更喜欢更优雅的解决方案
对Apple事件处理指南的进一步研究表明了问题所在:显然,当您使用IB将发送的操作分配给文本字段时,虽然该操作在用户按下return时启动,但该return不会注册为等效键,因此不会对应用程序的performKeyEquivalent查询响应yes,因此,该应用程序一直在寻找一个响应“是”的控件,因此它最终会自己调用该按钮
因此,我真正应该做的是将textfield子类化并重写其performKeyEquivalent方法,以便在keyCode为36(返回键的代码)时返回yes,如下所示:
- (BOOL) performKeyEquivalent:(NSEvent *)theEvent {
printf("\nThe keycode is %d", [theEvent keyCode]);
if ([theEvent keyCode] == 36)
return YES;
else
return NO;
}
但发生的情况是,即使目标textfield没有焦点,也会调用override方法。事实上,即使选择的按钮已经是第一响应者,它也会被调用。所以现在用户的返回总是被抢占,按钮的动作永远不会被调用
我修改了覆盖方法以检查第一响应者的身份:
[self.btnSaveAndNext setKeyEquivalent:@""];
- (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;
}
事实证明,当第一响应者的状态已经转移到按钮时,在执行textfield的sent操作后,会调用覆盖。因此,覆盖没有帮助
现在,我被困在这个答案的顶部。但是必须有某种方法来获取发送的操作,以完全捕获触发它的返回键事件…StackOverflow小妖精建议我结束这个问题。我将这个答案标记为已接受,因为事实上BOOL应该接受这个返回的乱码工作得很好,并且给了我很多控制。我也发现了一个问题——结果是更改IB inspector调色板中的“send action on”菜单项没有任何效果。我必须手动调用
[self.searchTextField.cell setSendsActionOneDediting:NO]
以避免两次执行操作。谢谢。这可能是一个更好的解决方案,比我公认的答案含糊不清。