NSOutlineView模仿Photoshop图层面板

时间:2012-06-02 20:10:47

标签: objective-c nstableview layer nsoutlineview

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

我正在尝试实现的目标:

我正在尝试创建一个模仿Photoshop图层面板行为的NSOutlineView(除了“图层”列是分层的)。我的outlineview是一个3列表,带有“Layer”列,“Visbility”列和“Lock”列。我已将“visibility”和“lock”列实现为NSImageCells,将“layer”列实现为自定义文本和图像单元格。

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

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

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

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

我一直在撞墙,试图让它上班一周。我已经阅读过控制器&单元编程指南,表视图编程指南,NSCell的类引用,NSActionCell,NSTableView,NSControl,NSOutlineView,以及NSOutlineViewDelegate和NSOutlineViewDataSource的协议引用......并且整个星期都在尝试不同的方法...而我只是没有搞清楚这个。

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

1 个答案:

答案 0 :(得分: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:message,并在拖动操作期间转到下一个 /em>...这意味着我无法使用该方法来确定何时完成拖动操作。

如果我覆盖

+(BOOL) prefersTrackingUntilMouseUp

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

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