3

当 NSTextField 通过按 Tab 键失去焦点时,我似乎找不到获得通知的方法。单击另一个控件或按 Enter 时,我会得到一个不错的textDidEndEditing,但如果我通过按 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 都被一个接一个地调用。但是,当将焦点从控件上移开时,两者都不是。

4

7 回答 7

6

“当单击另一个控件或按 Enter 时,我会得到一个不错的 textDidEndEditing,但如果我通过按 Tab 键更改焦点则不会。”

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

- (void)controlTextDidEndEditing:(NSNotification *)aNotification

...听 NSTextField 失去焦点,它工作正常。在你的情况下这可能吗?是不是以前坏了,现在被苹果修复了?

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

于 2011-04-03T14:33:43.283 回答
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
    }
} 

或者在 NSTextField 中按下 Enter-Key 时在执行操作中查看我的答案 ?

于 2013-12-04T07:53:59.333 回答
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;
}
于 2010-07-13T07:55:09.893 回答
0

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

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

  1. 单元格不能轻易确定它是否有焦点。

  2. 单元格无法通过其父级轻松确定它属于哪个更高级别的组件(例如文本字段或按钮)

  3. NSTextField 可以在获得第一响应者后立即辞职,这可能使它看起来好像失去了用户焦点,但实际上并没有。

由于我们重新利用了单元格的“突出显示”状态字段,为了将焦点状态传达给单元格,请务必从自定义 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
于 2013-02-16T19:46:44.663 回答
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

制作类并使您的对象成为他们的类。您将在 HMWindow.m 文件中的 NSLog 消息所在的文本字段中收到第一响应者更改的通知。如果您需要帮助了解它是如何工作的,请告诉我。

于 2010-07-07T11:26:58.863 回答
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
于 2015-07-16T19:11:15.700 回答
-1

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

于 2010-07-07T08:35:31.327 回答