按Tab键时NSTextField没有注意到失去焦点?

时间:2010-07-07 08:03:51

标签: cocoa focus nstextfield

当NSTextField按Tab键失去焦点时,我似乎找不到通知的方法。单击另一个控件或按Enter键时,我得到了一个很好的 textDidEndEditing ,但是如果我通过按Tab键更改焦点则没有。

还试图为此目的猛拉 KeyDown doCommandBySelector ,但我无处可去。

有什么想法吗?

提前致谢

修改

忘了提,但我也尝试了resignFirstResponder。这是我试过的代码:

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

奇怪的是,这里发生的事情是,当获得焦点时,一个接一个地调用firstFirstResponder和resignFirstResponder。但是当将焦点从控制中移开时,两者都不是。

7 个答案:

答案 0 :(得分:6)

  

"我得到了一个很好的textDidEndEditing   单击另一个控件或何时   按Enter键,但如果我改变则不行   按Tab键即可获得焦点。"

截至2011年4月,使用OS X 10.6库,我使用:

- (void)controlTextDidEndEditing:(NSNotification *)aNotification

...听取NSTextField失去焦点,并且它正常工作。在你的情况下这可能吗?它是否曾经被打破,但现在由Apple修复?

如果是这样,它的代码要少得多:)。

答案 1 :(得分:2)

好的,我找到了一种方法:使用窗口委托使窗口返回自定义字段编辑器。此字段编辑器会跟踪最后一个已激活的TextField,并在丢失firstResponder本身时调用其textDidEndEditting方法。以下是如何执行此操作的示例:

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

答案 2 :(得分:2)

你必须只做这个

对于关键标签

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?

答案 3 :(得分: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文件中。如果您需要帮助,了解它是如何工作的,请告诉我。

答案 4 :(得分:0)

这是一个如何指示自定义NSTextFieldCell(NSCell)应该绘制自己的边框和时间的适当时间的示例。聚焦环(在方法[NSTextFieldCell drawWithFrame:inView]中),通过'借用'单元格的高亮区域,在文本字段获得焦点时设置它,并在文本字段失去焦点时清除它(编辑完成)。

这种技术克服了一些问题:

  1. 细胞无法轻易确定它是否有焦点。

  2. 单元格无法轻易确定其所属的更高级别组件(例如文本字段或按钮)通过其父级跟踪

  3. NSTextField可以在获得第一个响应者后立即辞职,这可能会让它看起来好像失去了用户关注点。
  4. 由于我们重新设置了单元格的“突出显示”状态字段,为了将焦点状态传递给单元格,请确保从自定义NSTextFieldCell的[highlightColorWithFrame:inView:]方法返回nil。

    #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
    

答案 5 :(得分: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

答案 6 :(得分:-1)

NSTextField是NSResponder的子类。 NSResponder有一个方法 - (BOOL)resignFirstResponder。当NSTextField不再是第一响应者时,这将通知您...即。失去焦点。所以继承你的NSTextField并在那里做你的东西。