更改NSTableView备用行颜色

时间:2010-10-20 00:09:09

标签: objective-c cocoa macos interface-builder nstableview

我正在使用Interface Builder中的“Alternating Rows”选项在NSTableView上获取交替的行颜色。有没有办法改变交替行的颜色?

9 个答案:

答案 0 :(得分:7)

如果您想使用未记录的方式,请制作NSColor类别并覆盖_blueAlternatingRowColor,如下所示:

@implementation NSColor (ColorChangingFun)

+(NSColor*)_blueAlternatingRowColor
{
    return [NSColor redColor];
}

@end

或更改两种颜色,覆盖controlAlternatingRowBackgroundColors以返回您想要交替的颜色数组。

@implementation NSColor (ColorChangingFun)

+(NSArray*)controlAlternatingRowBackgroundColors
{
    return [NSArray arrayWithObjects:[NSColor redColor], [NSColor greenColor], nil];
}

@end

答案 1 :(得分:7)

找到了更好的方法here。该方法会覆盖NSTableView子类中的highlightSelectionInClipRect:方法,因此您可以使用所需的任何颜色来替换交替行。它不像使用NSColor类别那样苛刻,它只会影响您选择的表格视图。

答案 2 :(得分:4)

我将NSTableView子类化并实现了drawRow:clipRect:像这样......

- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
    NSColor *color = (row % 2) ? [NSColor redColor] : [NSColor whiteColor];
    [color setFill];
    NSRectFill([self rectOfRow:row]);
    [super drawRow:row clipRect:clipRect];
}

它似乎有用,但它很简单,我想知道我是否遗漏了什么。

答案 3 :(得分:3)

我想要一个像常规NSTableView一样工作的解决方案,包括对弹性滚动等的支持,所以我创建了一个NSTableView子类,其NSColor*属性称为{{1}然后覆盖alternateBackgroundColor方法,如下所示:

-drawBackgroundColorInClipRect:

答案 4 :(得分:3)

我不确定最近是如何添加的,或者它是否像您需要的那样灵活,但我注意到您可以在Xcode 4.6中的Interface Builder中指定“交替”行(可能更早)。

  1. 在Xcode中打开您的笔尖,然后选择NSTableViewNSOutlineView
  2. 在“实用工具”窗格中显示“属性”检查器(⎇⌘4)
  3. 请注意Highlight Alternating Rows复选框。
  4. enter image description here

答案 5 :(得分:1)

没有可设置的属性,但您可以响应委托方法-tableView:willDisplayCell:forTableColumn:row:并根据行号的均匀度设置单元格的背景颜色。

答案 6 :(得分:1)

Nate Thorn' answer对我来说非常合适。

在这里,重构为Swift:

import Foundation
import Cocoa
import AppKit

public class SubclassedTableView : NSTableView {

    private func
    alternateBackgroundColor() -> NSColor? {
        return NSColor.redColor() // Return any color you like
    }

    public override func
    drawBackgroundInClipRect(clipRect: NSRect) {

        if alternateBackgroundColor() == nil {
            // If we didn't set the alternate colour, fall back to the default behaviour
            super.drawBackgroundInClipRect(clipRect)
        } else {
            // Fill in the background colour
            self.backgroundColor.set()
            NSRectFill(clipRect)

            // Check if we should be drawing alternating coloured rows
            if usesAlternatingRowBackgroundColors {
                // Set the alternating background colour
                alternateBackgroundColor()!.set()

                // Go through all of the intersected rows and draw their rects
                var checkRect = bounds
                checkRect.origin.y = clipRect.origin.y
                checkRect.size.height = clipRect.size.height
                let rowsToDraw = rowsInRect(checkRect)
                var curRow = rowsToDraw.location
                repeat {
                    if curRow % 2 != 0 {
                        // This is an alternate row
                        var rowRect = rectOfRow(curRow)
                        rowRect.origin.x = clipRect.origin.x
                        rowRect.size.width = clipRect.size.width
                        NSRectFill(rowRect)
                    }

                    curRow++
                } while curRow < rowsToDraw.location + rowsToDraw.length

                // Figure out the height of "off the table" rows
                var thisRowHeight = rowHeight
                if gridStyleMask.contains(NSTableViewGridLineStyle.SolidHorizontalGridLineMask)
                   || gridStyleMask.contains(NSTableViewGridLineStyle.DashedHorizontalGridLineMask) {
                    thisRowHeight += 2.0 // Compensate for a grid
                }

                // Draw fake rows below the table's last row
                var virtualRowOrigin = 0.0 as CGFloat
                var virtualRowNumber = numberOfRows
                if numberOfRows > 0 {
                    let finalRect = rectOfRow(numberOfRows-1)
                    virtualRowOrigin = finalRect.origin.y + finalRect.size.height
                }
                repeat {
                    if virtualRowNumber % 2 != 0 {
                        // This is an alternate row
                        let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.size.width, height: thisRowHeight)
                        NSRectFill(virtualRowRect)
                    }

                    virtualRowNumber++
                    virtualRowOrigin += thisRowHeight
                } while virtualRowOrigin < clipRect.origin.y + clipRect.size.height

                // Draw fake rows above the table's first row
                virtualRowOrigin = -1 * thisRowHeight
                virtualRowNumber = -1
                repeat {
                    if abs(virtualRowNumber) % 2 != 0 {
                        // This is an alternate row
                        let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.size.width, height: thisRowHeight)
                        NSRectFill(virtualRowRect)
                    }

                    virtualRowNumber--
                    virtualRowOrigin -= thisRowHeight
                } while virtualRowOrigin + thisRowHeight > clipRect.origin.y
            }
        }
    }
}

答案 7 :(得分:1)

Swift 4 + 版本的AlternateRealist's answer

public class AlternateBgColorTableView: NSTableView {
    var alternateBackgroundColor: NSColor? = .red

    override public func drawBackground(inClipRect clipRect: NSRect) {
        // If we didn't set the alternate color, fall back to the default behavior
        guard let alternateBackgroundColor = alternateBackgroundColor else {
            super.drawBackground(inClipRect: clipRect)

            return
        }

        // Fill in the background color
        backgroundColor.set()
        clipRect.fill()

        // Check if we should be drawing alternating colored rows
        if usesAlternatingRowBackgroundColors {
            // Set the alternating background color
            alternateBackgroundColor.set()

            // Go through all of the intersected rows and draw their rects
            var checkRect = bounds
            checkRect.origin.y = clipRect.origin.y
            checkRect.size.height = clipRect.height
            let rowsToDraw = rows(in: checkRect)
            var currentRow = rowsToDraw.location

            repeat {
                if currentRow % 2 != 0 {
                    // This is an alternate row
                    var rowRect = rect(ofRow: currentRow)
                    rowRect.origin.x = clipRect.origin.x
                    rowRect.size.width = clipRect.width
                    rowRect.fill()
                }

                currentRow += 1
            } while currentRow < rowsToDraw.location + rowsToDraw.length

            // Figure out the height of "off the table" rows
            var thisRowHeight = rowHeight

            if gridStyleMask.contains(.solidHorizontalGridLineMask) || gridStyleMask.contains(.dashedHorizontalGridLineMask) {
                thisRowHeight += 2 // Compensate for a grid
            }

            // Draw fake rows below the table's last row
            var virtualRowOrigin: CGFloat = 0
            var virtualRowNumber = numberOfRows

            if numberOfRows > 0 {
                let finalRect = rect(ofRow: numberOfRows - 1)
                virtualRowOrigin = finalRect.origin.y + finalRect.height
            }

            repeat {
                if virtualRowNumber % 2 != 0 {
                    // This is an alternate row
                    let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.width, height: thisRowHeight)
                    virtualRowRect.fill()
                }

                virtualRowNumber += 1
                virtualRowOrigin += thisRowHeight
            } while virtualRowOrigin < clipRect.origin.y + clipRect.size.height

            // Draw fake rows above the table's first row
            virtualRowOrigin = -1 * thisRowHeight
            virtualRowNumber = -1

            repeat {
                if abs(virtualRowNumber) % 2 != 0 {
                    // This is an alternate row
                    let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.width, height: thisRowHeight)
                    virtualRowRect.fill()
                }

                virtualRowNumber -= 1
                virtualRowOrigin -= thisRowHeight
            } while virtualRowOrigin + thisRowHeight > clipRect.origin.y
        }
    }
}

答案 8 :(得分:0)

如果您希望将自定义颜色设置为与每行数据配对,那么由于上面的帖子,我发现了这种方法,并且该解决方案还致力于实现自定义替代行颜色(空行):

创建NSTableView的子类:

ColoredRowTableView.h

   @protocol ColoredRowTableViewDelegate <NSTableViewDelegate>
   -(NSColor *)colorForRow:(NSInteger)row;
   @end
   @interface ColoredRowTableView : NSTableView
   @end

在ColoredRowTableView.m中

- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
    if (row == [self selectedRow])
    {
        [super drawRow:row clipRect:clipRect];
         return;
    }
    NSColor *color = [(id<ColoredRowTableViewDelegate>)[self delegate] colorForRow:row];
    [color setFill];
    NSRectFill([self rectOfRow:row]);
    [super drawRow:row clipRect:clipRect];
}

然后在您的表视图委托中:

#import "ColoredRowTableView.h"
@interface MyTableViewDelegate : NSViewController <ColoredRowTableViewDelegate>
// instead of <NSTableViewDelegate>

在您的委托中实现colorForRow:方法。如果目标仅是提供备用行,则可以返回基于行号的颜色(如果是偶数或奇数)。 同样不要忘记在界面构建器中将表视图的类更改为ColoredRowTableView