NSTextField:当用户在文本框外单击时结束编辑。

5

我有一个NSTextField,根据用户的操作我会将其设置为可编辑。当用户在窗口内点击文本框以外的任何地方时,我希望结束编辑。

这似乎很简单,但我无法做到。我已经实现了controlTextDidEndEditingtextDidEndEditing,但是没有成功,特别是当我点击不接受第一响应者状态的用户界面元素时。

4个回答

2

每个NSEvent会通过NSWindow的sendEvent:方法进行传递。

您可以创建自定义的NSWindow并覆盖sendEvent:方法。如果有鼠标按下事件,可以通过NSNotificationCenter广播它:

- (void)sendEvent:(NSEvent *)event {
    [super sendEvent:event];
    if (event.type == NSLeftMouseDown) {
        [[NSNotificationCenter defaultCenter] postNotificationName:kCustomWindowMouseDown object:self userInfo:@{@"event": event}];
    }
}

在引用NSTextField的ViewController中,观察此通知:
 [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(customWindowMouseDown:)
                                                 name:kCustomWindowMouseDown
                                               object:self.view.window];


如果鼠标按下事件发生在文本框之外,则结束编辑:

- (void)customWindowMouseDown:(id)sender {
    NSNotification *notification = (NSNotification *) sender;

    NSEvent *event = notification.userInfo[@"event"];
    NSPoint locationInWindow = event.locationInWindow;

    if ([self.view.window.firstResponder isKindOfClass:NSTextView.class]) {
        NSTextView *firstResponder = (NSTextView *) self.view.window.firstResponder;

        //we only care about the text field referenced by current ViewController
        if (firstResponder.delegate == (id <NSTextViewDelegate>) self.textField) {

            NSRect rect = [self.textField convertRect:self.textField.bounds toView:nil];

            //end editing if click out side
            if (!NSPointInRect(locationInWindow, rect)) {
                [self.view.window makeFirstResponder:nil];
            }

        }
    }
}

0
您可以编写一个 NSView 的子类并编写以下方法,然后将 Nib 文件中 NSWindow 中 NSView 的类更改为该子类。
 - (void)mouseDown:(NSEvent *)event 
    {
         [text setEditable:NO];
         NSLog(@"mouseDown");
    }

我已经考虑过了。问题在于窗口的UI包含更多控件,其中一些已经处理了mouseDown:事件。我无法修改这些方法的行为。有没有办法拦截所有鼠标事件,无论它们将在何处处理? - Mark
你尝试过使用hittest吗?它可以拦截所有鼠标事件。 - vignesh kumar

0

可能会有点不太好看,但你可以在“文本字段的外部区域”创建一个大的透明按钮。当编辑开始时显示它,当编辑结束时隐藏它。如果用户点击此按钮,则停止编辑(并隐藏按钮)。

当我需要快速解决问题时,这为我解决了那个问题。


0

我会改进Vignesh Kumar的答案,以适用于无法对包含视图的窗口进行子类化的情况。

对于所有处理mouseDown的子视图/控件,包括超级视图本身,请实现:

- (void)mouseDown:(NSEvent *)event
{
    [[self window] makeFirstResponder:self];

    [super mouseDown:event];
}

对于一些控件,比如按钮,你可以进行更改

- (void)mouseDown:(NSEvent *)event
{
    [[self window] makeFirstResponder:[self superview]];

    [super mouseDown:event];
}

否则可能会出现焦点环


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接