2011-02-23 106 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