【问题标题】:NSTableView: How to draw a custom separators before and after a selected rowNSTableView:如何在选定行之前和之后绘制自定义分隔符
【发布时间】:2012-01-16 21:58:20
【问题描述】:

这是我在这里的第一个问题,我会尽量做到清楚。

我想在基于视图的 NSTableView 中的选定行上绘制自定义渐变,同时添加微妙的凸起效果。为此,我需要为所选行之前和之后的网格线使用较深的颜色(例如,请参阅here)。我已经覆盖了 NSTableRowView 中的drawSeparatorInRect: 方法来为选定的行绘制自定义分隔线(使用isSelected 方法作为标志),但我不能对上面/下面的行做同样的事情(因为我在底部/顶部画线)。

我尝试了几种方法来告诉最近的行它应该绘制一条较暗的分隔线但没有成功,因为显示步骤不遵循相同的顺序(我在drawSeparatorInRect: 中使用 NSLogs 检查了它,似乎当你滚动一点时,这个顺序会改变)。所以,有时(主要是在滚动之后)该行不知道它应该使用较深的颜色,因为它在所选行之前绘制自己(我认为此时,所选行还不知道它已被选中,否则我不明白发生了什么)。

我尝试过的一些事情:

  1. 在所选行的drawSeparatorInRect: 方法中,我尝试访问兄弟视图 ([superview subviews]) 并强制上一个/下一个重新绘制自己。
  2. NSTableView 子类中,当selectedIndexes 更改时直接修改最近的行。
  3. 从其drawSeparatorInRect: 方法中在选定行之外绘制线,显示here

请注意,我这样做是有:一个行视图询问是否选择了上一个/下一个,一个 closestRowIsSelected 标志或外部调用一个方法来“强制”深色。

我现在所拥有的是选定的行同时绘制了顶部和底部边框,因此其中一个被放置在上一行/下一行中......它很微妙,但它仍然存在。

任何帮助都会受到欢迎。

提前谢谢你。

我没有发布任何代码,因为问题不存在(它只是用红色调用[NSBezierPath fillRect:rect]),我想......所以我没有什么可显示的。

【问题讨论】:

    标签: cocoa nstableview


    【解决方案1】:

    我也试过了,发现drawSeparatorInRect:真的只能画它的底部分隔线,因为顶部分隔线的位置(与前一行的底部分隔线相同)在外面一个像素(上)该行的clipRect。

    但是,我通过继承 NSTableRowView 并使用 drawSeparatorInRect: 使其工作,如下所示:

    - (void)drawSeparatorInRect:(NSRect)dirtyRect
    {
        // Define our drawing colors
        NSColor *normalColor = [NSColor colorWithCalibratedWhite:0.76 alpha:1.0]; // Default separator color
        NSColor *selectedTopColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the top separator line of selected row
        NSColor *selectedBottomColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the bottom separator line of selected row
    
        // Define coordinates of separator line
        NSRect drawingRect = [self frame]; // Ignore dirtyRect
        drawingRect.origin.y = drawingRect.size.height - 1.0;
        drawingRect.size.height = 1.0; // Height of the separator line we're going to draw at the bottom of the row
    
        // Get the table view and info on row index numbers
        NSTableView *tableView = (NSTableView*)[self superview]; // The table view the row is part of
        NSInteger selectedRowNumber = [tableView selectedRow];
        NSInteger ownRowNumber = [tableView rowForView:self];
    
        // Set the color of the separator line
        [normalColor set]; // Default
        if (([self isSelected]) && ((selectedRowNumber + 1) < [tableView numberOfRows])) [selectedBottomColor set]; // If the row is selected, use selectedBottomColor
        if ((![self isSelected]) && (selectedRowNumber > 0) && (ownRowNumber == (selectedRowNumber-1))) [selectedTopColor set]; // If the row is followed by the selected row, draw its bottom separator line in selectedTopColor
    
        // Draw separator line
        NSRectFill (drawingRect);
    
        // If the row is selected, tell the preceding row to redraw its bottom separator line (which is also the top line of the selected row)
        if (([self isSelected]) && (selectedRowNumber > 0)) [tableView setNeedsDisplayInRect:[tableView rectOfRow:selectedRowNumber-1]];
    }
    

    此方法将(仅)绘制自己的底部分隔线。如果是选中的行,它会不使用默认颜色绘制线条,而是突出显示,然后它还会告诉前一行重新绘制其分隔线,即与所选行的顶部分隔线相同。

    为了使其正常工作,一旦选择移动,所选行上方的行需要重新绘制其底部分隔线。我通过在 NSTableView 委托中使用此方法实现了这一点:

    // Tell the row above the row which is going to loose the selection to redraw its bottom separator line
    - (BOOL)selectionShouldChangeInTableView:(NSTableView *)aTableView
    {
        NSInteger selectedRowNumber = [aTableView selectedRow];
        if (selectedRowNumber > 0) {
        [aTableView setNeedsDisplayInRect:[aTableView rectOfRow:selectedRowNumber-1]];
        }
        return YES;
    }
    

    这个委托方法告诉仍然选中的行上方的行重新绘制其分隔线。在选择更改之前立即调用它。

    【讨论】:

    • 实际上Apple文档证明是正确的: NSTableRowView 的默认行为是在行的底部绘制分隔线,而不是在顶部。我已经相应地编辑了上面的代码示例。
    • 非常感谢,它确实符合我的要求。但是,每当我选择一行或滚动 tableview 时,前一个选择的行会多次重绘自身,这会产生超粗体文本和其他奇怪的效果。我错过了什么吗?
    • 我让它与我的旧代码完美配合。但是,我将位于drawSeparatorInRect: 方法末尾的强制前面的单元格视图自行绘制的代码移到了一个委托方法,该方法为我提供了新的选定行(我使用了tableView:shouldSelectRow:)。再次感谢您的帮助。
    • 我宁愿将setNeedsDisplayInRect:调用放在outlineViewSelectionDidChange:委托方法中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2019-12-19
    • 2017-03-18
    • 2023-04-01
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多