2010-07-07 44 views
1

當NSTextField按下Tab鍵失去焦點時,我似乎無法找到通知的方法。當點擊另一個控件或按Enter鍵時,我會得到一個不錯的textDidEndEditing,但如果通過按下Tab鍵更改焦點,則不會。NSTextField在按Tab鍵時沒有注意到失去焦點?

也試過抽出的KeyDowndoCommandBySelector用於此目的,但我毫無進展。

任何想法?

在此先感謝

編輯:

忘了提,但我想resignFirstResponder了。這是我試過的代碼:

- (BOOL)resignFirstResponder 
{ 
    NSRunAlertPanel(@"", @"Lost Focus",@"OK", nil, nil); 
    return [super resignFirstResponder]; 
} 
- (BOOL)becomeFirstResponder 
{ 
    NSRunAlertPanel(@"", @"Got focus",@"OK", nil, nil); 
    return [super becomeFirstResponder]; 
} 

奇怪的是,這裏所發生的是,越來越焦點時,既becomeFirstResponder和resignFirstResponder被稱爲一前一後。但是,當把焦點從控制轉向時,它們都不是。

回答

2

好吧,我找到了一種方法:使用窗口委託使窗口返回一個自定義字段編輯器。這個字段編輯器跟蹤最後一個被激活的TextField,並在失去firstResponder本身時調用它的textDidEndEditing方法。下面是如何做到這一點的例子:

#import <Cocoa/Cocoa.h> 
#import <AppKit/AppKit.h> 


@interface MyTextField : NSTextField 
- (BOOL)resignFirstResponder; 
- (void)textDidEndEditing:(NSNotification *)notification; 
@end 

@interface MyFieldEditor : NSTextView 
{ 
    MyTextField * lastBox; 
} 
-(void) setLastEditBox:(MyTextField*) box; 
@end 

@interface MyWindowDelegate : NSWindowController 
{ 
    MyFieldEditor *fieldEditor; 
} 
@end 



@implementation MyFieldEditor 

-(void) setLastEditBox:(MyTextField*) box{ lastBox = box; } 

-(id)init 
{ 
    if (self = [super init]) 
     [self setFieldEditor:YES]; 

    return self; 
} 

- (BOOL)resignFirstResponder 
{ 
    // Activate the last active editbox editting-end event 
    if(lastBox != nil) 
    { 
     [lastBox textShouldEndEditing:self]; 
     lastBox = nil; 
    } 

    return [super resignFirstResponder]; 
} 

@end 


@implementation MyWindowDelegate 

-(id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client 
{ 
    if(fieldEditor == nil) // Return our special field editor 
     fieldEditor = [[[MyFieldEditor alloc] autorelease] init]; 
    return fieldEditor; 
} 
@end 


@implementation MyTextField 

- (BOOL)resignFirstResponder 
{ 
    // We're losing first responder, inform the field editor that this was the last edit box activated 
    MyFieldEditor* myTf = (MyFieldEditor*) [[self window] fieldEditor:YES forObject:self]; 
    [myTf setLastEditBox:self]; 
    return [super resignFirstResponder]; 
} 

- (void)textDidEndEditing:(NSNotification *)notification; 
{ 
    [super textDidEndEditing:notification]; 
    [self setStringValue:@"RECEIVED ENDEDITING"]; 
} 

@end 




int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSApplication *app = [NSApplication sharedApplication]; 

    NSRect frame = NSMakeRect(100, 100, 200, 150); 

    // Create the window 
    NSWindow* window = [[[NSWindow alloc] autorelease ] initWithContentRect:frame styleMask:NSClosableWindowMask|NSResizableWindowMask 
                 backing:NSBackingStoreBuffered defer:NO]; 

    [window setDelegate:[[MyWindowDelegate alloc] autorelease]]; 


    MyTextField * tf = [ [[ MyTextField alloc ] autorelease] initWithFrame: NSMakeRect(30.0, 100.0, 150.0, 22.0) ]; 
    [ [ window contentView ] addSubview: tf ]; 

    MyTextField * tf2 = [ [[ MyTextField alloc ] autorelease] initWithFrame: NSMakeRect(30.0, 40.0, 150.0, 22.0) ]; 
    [ [ window contentView ] addSubview: tf2 ]; 

    [window makeKeyAndOrderFront: window]; 

    [app run]; 
    [pool release]; 

    return 0; 
} 
-1

NSTextField是NSResponder的子類。 NSResponder有一個方法 - (BOOL)resignFirstResponder。當NSTextField不再是第一響應者時,會通知您...即,失去了重點。因此,您的NSTextField子類並在那裏做你的東西。

+0

見更新的帖子。我曾嘗試過,但它不像預期的那樣表現 – hasvn 2010-07-07 09:31:23

+3

我明白爲什麼了。一個窗口有一個字段編輯器,用於窗口中需要文本的所有te對象。當你輸入一些東西時,你實際上是在字段編輯器中輸入它,而不是文本字段本身。因此,文本字段成爲第一響應者,然後立即辭去第一響應者,因爲字段編輯器成爲第一響應者。 – regulus6633 2010-07-07 11:15:20

0

隨着我在另一篇文章中提到的理解,我想出了一個答案。這有點複雜,但它的工作原理。你必須繼承NSTextField和NSWindow,因爲你需要兩者的信息來設置它。這裏的子類: HMTextField.h

#import <Foundation/Foundation.h> 

@interface HMTextField : NSTextField { 

} 

@end 

HMTextField.m

#import "HMTextField.h" 
#import "HMWindow.h" 

@implementation HMTextField 

- (BOOL)becomeFirstResponder { 
    [(HMWindow*)[self window] setTfBecameFirstResponder:YES]; 
    return [super becomeFirstResponder]; 
} 

@end 

HMWindow.h

#import <Foundation/Foundation.h> 

@interface HMWindow : NSWindow { 
    BOOL tfIsFirstResponder, tfBecameFirstResponder; 
} 

@property (nonatomic, readwrite, assign) BOOL tfBecameFirstResponder; 

@end 

HMWindow.m

#import "HMWindow.h" 

@implementation HMWindow 

@synthesize tfBecameFirstResponder; 

-(id)init { 
    if (self = [super init]) { 
     tfIsFirstResponder = NO; 
    } 
    return self; 
} 

- (NSResponder *)firstResponder { 
    id fr = [super firstResponder]; 

    if ([fr isEqualTo:[self fieldEditor:NO forObject:nil]]) { 
     tfIsFirstResponder = YES; 
    } else { 
     if (tfIsFirstResponder && tfBecameFirstResponder) { 
      NSLog(@"the text field stopped being first responder"); 
      tfBecameFirstResponder = NO; 
     } 
     tfIsFirstResponder = NO; 
    } 

    return fr; 
} 

@end 

製作類,使你的目標他們的班級。您將收到文本字段中第一個響應者更改的通知,其中NSLog消息位於HMWindow.m文件中。如果您需要幫助瞭解它的工作原理,請告訴我。

+0

問題是,這是一個交互式應用程序,它有一堆TextField,spinbox和其他東西,並且每次用戶停止修改控件時都需要更新視圖。也就是說,當* textDidEndEditing *事件觸發時,我們更新視圖。而且這個效果很好,除了當用Tab鍵改變焦點時這個事件沒有被觸發。 這意味着我們需要支持每個窗口的多個文本框,並且我們需要在焦點更改發生時通過事件通知,而不是像以下解決方案那樣查詢它:-S 感謝建議反正 – hasvn 2010-07-07 13:42:55

5

「我知道當 單擊另一個控制或當 按Enter一個不錯的textDidEndEditing,但如果我按Tab鍵對焦變化 。」

截至2011年4月,OS X 10。6庫,我正在使用:

- (void)controlTextDidEndEditing:(NSNotification *)aNotification 

...監聽NSTextField失去焦點,它的工作正常。這在你的情況下可能嗎?這是否曾經被破壞,但現在已被Apple修復?

如果是這樣,它的代碼少得多:)。

+0

用10.7 SDK,10.6部署對象也適合我。 – ctpenrose 2012-04-26 07:05:45

0

以下是如何以指示適當的時間自定義NSTextFieldCell(的NSCell)應該得出自己擋板&聚焦環(在該方法中[NSTextFieldCell drawWithFrame:inView])的一個例子,通過「借」細胞的精彩畫面字段,設置當文本字段獲得焦點並在文本字段失去焦點時清除它(編輯完成)。

該技術克服了一些問題:

  1. 細胞不能輕易確定其是否具有焦點。

  2. 細胞不能容易地確定哪個更高級別的組件(例如文本域或按鈕)它屬於通過其父

  3. 的NSTextField跟蹤能夠瞬時辭職第一響應獲得它之後,這可能使它看起來像它沒有時就失去了用戶的注意力。

因爲我們正在重新考慮對細胞的「高亮」狀態領域中,爲了焦點狀態傳達給細胞,務必從定製NSTextFieldCell的返回nil [highlightColorWithFrame:inView:]方法。

#import "CustomTextField.h" 

@implementation CustomTextField 

-(BOOL)becomeFirstResponder { 
    ((NSTextFieldCell *)self.cell).highlighted = true; 
    return [super becomeFirstResponder]; 
} 

-(void)textDidEndEditing:(NSNotification *)notification { 
    ((NSTextFieldCell *)self.cell).highlighted = false; 
    [super textDidEndEditing:notification]; 
} 
@end 
2

你所要做的只是這

對於TAB鍵

self.textfield.delegate = self; 

,然後實現此方法

- (void)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector 
{ 
    NSLog(@"Selector method is (%@)", NSStringFromSelector(commandSelector)); 
    if (commandSelector == @selector(insertTab:)) { 
     //Do something against TAB key 
     //Or Call a Method 
    } 
} 

或見我的答案在 Execute an Action when the Enter-Key is pressed in a NSTextField?

+0

當我實現這個時,像esc和''backspace''這樣的按鈕停止工作。實際上你不需要實現委託方法。只需將您的文本字段連接到界面構建器中的委託,並確保「拒絕First Responder」未被選中。 – Supertecnoboff 2017-10-17 11:00:07

0

複雜的答案。有一個更簡單的方法來做到這一點。

不要忘記將您的NSTextField繼承爲NotificableTextField並將其委託設置爲您的視圖控制器。

NotificableTextField.h

#import <Cocoa/Cocoa.h> 

@protocol NotificableTextFieldDelegate <NSObject> 
@optional 
- (void)textFieldStartedEditing:(NSTextField *)textField; 
- (void)textFieldEndedEditing:(NSTextField *)textField; 
@end 

@interface NotificableTextField : NSTextField 
@end 

NotificableTextField.m

#import "NotificableTextField.h" 

@implementation NotificableTextField 

- (void)awakeFromNib 
{ 
    [super awakeFromNib]; 

    self.target = self; 
    self.action = @selector(inputEnd); 
} 

- (BOOL)becomeFirstResponder 
{ 
    BOOL status = [super becomeFirstResponder]; 
    if (status && [self.delegate respondsToSelector:@selector(textFieldStartedEditing:)]) 
     [(id<NotificableTextFieldDelegate>)self.delegate textFieldStartedEditing:self]; 
    return status; 
} 

- (void)inputEnd 
{ 
    if ([self.delegate respondsToSelector:@selector(textFieldEndedEditing:)]) 
     [(id<NotificableTextFieldDelegate>)self.delegate textFieldEndedEditing:self]; 
} 

@end