在基于视图的表视图中响应文本字段中的鼠标事件

pau*_*kow 27 cocoa nstextfield nstableview mousedown

我在自定义视图中有文本字段NSOutlineView.编辑其中一个单元格需要单击,暂停和另一次单击.第一次单击选择表视图行,第二次单击单击在字段中绘制光标.双击单元格(允许您在基于单元格的表格视图中进行编辑)仅选择该行.

我想要的行为:单击一下即可更改选择并进行编辑.

我需要覆盖什么才能获得此行为?

我读过其他一些帖子:

  • NSTextField 轻量级的模式似乎并不适用于基于视图的表视图,其中电池的观点都是从笔尖实例化.
  • 我试过NSTextField这个解决方案描述的子类化,但我mouseDown没有调用我的重写方法.被覆盖awakeFromNibviewWillDraw(在这篇文章中提到)称为.当然,mouseDown如果我将文本字段放在表视图之外的某处,则会调用它.

相比之下,NSSegmentedControl我的单元格视图中的a更改其值而不先选择行.


以下是根据公认的回复改编的工作解决方案:

在大纲视图子类中:

-(void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent];

    // Forward the click to the row's cell view
    NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
    NSInteger row = [self rowAtPoint:selfPoint];
    if (row>=0) [(CellViewSubclass *)[self viewAtColumn:0 row:row makeIfNecessary:NO]
            mouseDownForTextFields:theEvent];
}
Run Code Online (Sandbox Code Playgroud)

在表格单元格视图子类中:

// Respond to clicks within text fields only, because other clicks will be duplicates of events passed to mouseDown
- (void)mouseDownForTextFields:(NSEvent *)theEvent {
    // If shift or command are being held, we're selecting rows, so ignore
    if ((NSCommandKeyMask | NSShiftKeyMask) & [theEvent modifierFlags]) return;
    NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
    for (NSView *subview in [self subviews])
        if ([subview isKindOfClass:[NSTextField class]])
            if (NSPointInRect(selfPoint, [subview frame]))
                [[self window] makeFirstResponder:subview];
}
Run Code Online (Sandbox Code Playgroud)

Dov*_*Dov 15

我会尝试返回帮助 ...子类NSOutlineView和覆盖-mouseDown:如下:

- (void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent];

    // Only take effect for double clicks; remove to allow for single clicks
    if (theEvent.clickCount < 2) {
        return;
    }

    // Get the row on which the user clicked
    NSPoint localPoint = [self convertPoint:theEvent.locationInWindow
                                   fromView:nil];
    NSInteger row = [self rowAtPoint:localPoint];

    // If the user didn't click on a row, we're done
    if (row < 0) {
        return;
    }

    // Get the view clicked on
    NSTableCellView *view = [self viewAtColumn:0 row:row makeIfNecessary:NO];

    // If the field can be edited, pop the editor into edit mode
    if (view.textField.isEditable) {
        [[view window] makeFirstResponder:view.textField];
    }
}
Run Code Online (Sandbox Code Playgroud)


trs*_*rss 14

有同样的问题.经过多次努力,当我选择None与IB中的表格视图选项的默认值Regular(其他选项Source List)时,它神奇地起作用Highlight!

另一种选择是/sf/answers/950562861/上的解决方案,与此相比,它似乎更具体,但有点hacky.


cor*_*unn 6

您确实想重写 validateProposeFirstResponder 并允许根据您的逻辑创建(或不创建)特定的第一响应者。NSTableView 中的实现(有点)像这样(我将其重写为伪代码):

- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {

// We want to not do anything for the following conditions:
// 1. We aren't view based (sometimes people have subviews in tables when they aren't view based)
// 2. The responder to valididate is ourselves (we send this up the chain, in case we are in another tableview)
// 3. We don't have a selection highlight style; in that case, we just let things go through, since the user can't appear to select anything anyways.
if (!isViewBased || responder == self || [self selectionHighlightStyle] == NSTableViewSelectionHighlightStyleNone) {
    return [super validateProposedFirstResponder:responder forEvent:event];
}

if (![responder isKindOfClass:[NSControl class]]) {
    // Let any non-control become first responder whenever it wants
    result = YES;
    // Exclude NSTableCellView. 
    if ([responder isKindOfClass:[NSTableCellView class]]) {
        result = NO;
    }

} else if ([responder isKindOfClass:[NSButton class]]) {
    // Let all buttons go through; this would be caught later on in our hit testing, but we also do it here to make it cleaner and easier to read what we want. We want buttons to track at anytime without any restrictions. They are always valid to become the first responder. Text editing isn't.
    result = YES;
} else if (event == nil) {
    // If we don't have any event, then we will consider it valid only if it is already the first responder
    NSResponder *currentResponder = self.window.firstResponder;
    if (currentResponder != nil && [currentResponder isKindOfClass:[NSView class]] && [(NSView *)currentResponder isDescendantOf:(NSView *)responder]) {
        result = YES;
    }
} else {
    if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown) {
        // If it was a double click, and we have a double action, then send that to the table
        if ([self doubleAction] != NULL && [event clickCount] > 1) {
           [cancel the first responder delay];
        }
   ...
          The code here checks to see if the text field 
        cell had text hit. If it did, it attempts to edit it on a delay. 
        Editing is simply making that NSTextField the first responder.
        ...

     }
Run Code Online (Sandbox Code Playgroud)