2

我有一个关于在 NSTableViews/NSOutlineViews 中实现一些特定行为的问题。

我想要达到的目标:

我正在尝试创建一个模仿 Photoshop 图层面板行为的 NSOutlineView(“图层”列是分层的除外)。我的大纲视图是一个 3 列表,其中包含“层”列、“可见性”列和“锁定”列。我已经将“可见性”和“锁定”列实现为 NSImageCells,并将“层”列实现为自定义文本和图像单元格。

具体来说,这是我正在努力实现的行为:

  • 就像 Photoshop 一样,用户应该能够单击可见性(眼球)图标并向上或向下拖动到不同的行,以根据单击的第一行的可见性“打开”或“关闭”其他行的可见性。 . 确切地说 Photoshop 是如何隐藏和显示图层的。请注意,当表中有很多行时,应支持自动滚动。

  • 就像 Photoshop 一样,当“图层”列中的一行或多行被选中时,可见性/锁定列的后面不应有高亮条(也就是说,行高亮不应穿过它们的列)。

  • 在“可见性”或“锁定”列中单击和/或拖动不应更改表的选择...仅更改它们的状态,如上所述。

一个星期以来,我一直在用头撞墙,试图让它发挥作用。我已经阅读了控件和单元格编程指南、表格视图编程指南、NSCell、NSActionCell、NSTableView、NSControl、NSOutlineView 的类参考,以及 NSOutlineViewDelegate 和 NSOutlineViewDataSource 的协议参考……并且整个星期都在尝试不同的方法。 .而且我只是没有弄清楚这一点。

有人可以引导我朝着正确的方向前进吗?在此先感谢您的帮助!

4

1 回答 1

2

通过一些额外的网络搜索和实验,我可以回答我自己的大部分问题:

仅突出显示 NSOUTLINEVIEW 中的第一列

通过继承 NSOutlineView 并实现,我能够使选择突出显示仅出现在第一列的选定行上

- (void)highlightSelectionInClipRect:(NSRect)clipRect
{
    NSRange visibleRowIndexes = [self rowsInRect:clipRect];
    NSIndexSet *selectedRowIndexes = [self selectedRowIndexes];

    NSInteger currentRow = visibleRowIndexes.location;
    NSInteger lastRow = currentRow + visibleRowIndexes.length;

    NSColor *highlightColor;

    //Determine color of selection bar based on key/main/first responder status.
    if (self == [[self window] firstResponder] && [[self window] isMainWindow] && [[self window] isKeyWindow]) {
        highlightColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.3 alpha:1.0];
    } else
        highlightColor = [NSColor lightGrayColor];
    }
    [highlightColor setFill];

    //Get the Rect of only the name column. This is the only column that will be highlighted.
    //We'll intersect this rect with the row rect for the area to fill in.
    NSInteger nameColumn = [self columnWithIdentifier:@"name"];
    NSRect nameColumnRect = [self rectOfColumn:nameColumn];

    while (currentRow < lastRow) {
        if ([selectedRowIndexes containsIndex:currentRow]) {
            NSRect drawRect = NSIntersectionRect([self rectOfRow:currentRow], nameColumnRect);
            NSRectFill(drawRect);
        }
        currentRow++;
    }
}

需要注意的是,我必须重写我的自定义 NSCell 子类的 drawInteriorWithFrame:inView: 方法以防止它绘制标准高亮,如下所示:

-(void) drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    //do drawing here...don't call super.
}

所以有一个解决部分问题的方法。如果这不是“正确”的方式,请告诉我:)。

在 VIS/LOCK 列中单击/拖动不应更改选择 我现在已经确定我应该在

-(NSIndexSet *) outlineView:(NSOutlineView *)outlineView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes

方法。如果我处于源自可见性或锁定列的拖动中间,我只需返回当前 selectedRows 以保持选择相同。我还没有实现这个,但是一旦我解决了我的最终问题(见下文),它应该很容易。

在可见性/锁定列中向上或向下拖动以更改其状态

我和这个非常接近。在我的自定义 NSCell 中,我重写了以下三种方法:

-(BOOL) startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
-(BOOL) continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
-(void) stopTracking:(NSPoint) lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag

我要解决我的最后一个问题,这里是:我需要知道我何时在拖动操作中以及拖动操作何时完成。我有两种方法可以做到这一点:

如果我覆盖

+(BOOL) prefersTrackingUntilMouseUp

在我的 NSCell 子类中(所以它返回默认的 NO 值),然后我每次离开一个单元格并在拖动操作期间转到下一个单元格时都会收到一个 stopTracking:at:inView:mouseIsUp: 消息......这意味着我可以'不要使用该方法来确定拖动操作何时完成。

相反,如果我确实覆盖

+(BOOL) prefersTrackingUntilMouseUp

并返回 YES,我得到一个 stopTracking:... 仅在鼠标启动时调用,这很好...但问题是表格似乎没有更新 mouseDown 上的单元格的 UI 或当我拖动时细胞内。例如,在 startTracking:... 方法中,如果我将单元格的 objectValue 设置为 nil(以便不再显示其图像),直到鼠标按钮返回或光标离开细胞。(当 prefersTrackingUntilMouseUp 返回 NO 时,它会立即更新)。

因此,我既需要能够立即(在 mouseDown 上)更新单元格的 UI,也需要有办法知道拖动操作何时完成。这是拼图的最后一块。任何人都可以帮忙吗?

于 2012-06-03T19:31:08.320 回答