在Cocoa中如何更改NSTableView中的高亮颜色?

15

我正在开发一个Cocoa应用程序,遇到了一些高亮问题。在MAC OS X应用程序中,标准的高亮颜色是蓝色,但由于设计概念的原因,我需要使用绿色作为高亮颜色,这不适合我的应用程序。

我尝试对NSTableView进行子类化并重写方法

- (void)highlightSelectionInClipRect:(NSRect)clipRect

但是它没有起作用。

如何解决这个问题?

3个回答

19

我正在使用这个,目前为止完美运行:

- (void)highlightSelectionInClipRect:(NSRect)theClipRect
{

        // this method is asking us to draw the hightlights for 
        // all of the selected rows that are visible inside theClipRect

        // 1. get the range of row indexes that are currently visible
        // 2. get a list of selected rows
        // 3. iterate over the visible rows and if their index is selected
        // 4. draw our custom highlight in the rect of that row.

    NSRange         aVisibleRowIndexes = [self rowsInRect:theClipRect];
    NSIndexSet *    aSelectedRowIndexes = [self selectedRowIndexes];
    int             aRow = aVisibleRowIndexes.location;
    int             anEndRow = aRow + aVisibleRowIndexes.length;
    NSGradient *    gradient;
    NSColor *       pathColor;

        // if the view is focused, use highlight color, otherwise use the out-of-focus highlight color
    if (self == [[self window] firstResponder] && [[self window] isMainWindow] && [[self window] isKeyWindow])
    {
        gradient = [[[NSGradient alloc] initWithColorsAndLocations:
                     [NSColor colorWithDeviceRed:(float)62/255 green:(float)133/255 blue:(float)197/255 alpha:1.0], 0.0, 
                     [NSColor colorWithDeviceRed:(float)48/255 green:(float)95/255 blue:(float)152/255 alpha:1.0], 1.0, nil] retain]; //160 80

        pathColor = [[NSColor colorWithDeviceRed:(float)48/255 green:(float)95/255 blue:(float)152/255 alpha:1.0] retain];
    }
    else
    {
        gradient = [[[NSGradient alloc] initWithColorsAndLocations:
                     [NSColor colorWithDeviceRed:(float)190/255 green:(float)190/255 blue:(float)190/255 alpha:1.0], 0.0, 
                     [NSColor colorWithDeviceRed:(float)150/255 green:(float)150/255 blue:(float)150/255 alpha:1.0], 1.0, nil] retain];

        pathColor = [[NSColor colorWithDeviceRed:(float)150/255 green:(float)150/255 blue:(float)150/255 alpha:1.0] retain];
    }

        // draw highlight for the visible, selected rows
    for (aRow; aRow < anEndRow; aRow++)
    {
        if([aSelectedRowIndexes containsIndex:aRow])
        {
            NSRect aRowRect = NSInsetRect([self rectOfRow:aRow], 1, 4); //first is horizontal, second is vertical
            NSBezierPath * path = [NSBezierPath bezierPathWithRoundedRect:aRowRect xRadius:4.0 yRadius:4.0]; //6.0
                [path setLineWidth: 2];
                [pathColor set];
                [path stroke];

            [gradient drawInBezierPath:path angle:90];
        }
    }
}

这个方法完美地运行了,非常感谢!!!起初我忘记在IB中将Highlight更改为Source list,现在它可以工作了,太棒了。 - Artem
2
alloc-init 序列之后,您不应该需要使用 retain - adib
它对我有用,我刚刚测试过了...好的,对于ARC你需要移除保留,这不是什么大问题。 - Bogdan
4
这仅适用于基于单元格的表视图,基于视图的表视图需要在NSTableRowView中进行。 - Micha Mazaheri

10
我也花了数小时寻找答案,尽管我发现了许多碎片,但它们都不完整。 所以在这里我提交另一种方法,我正在成功使用它。
1)将NSTableView selectionHighLightStyle设置为None 这是必要的,以确保OS X不仅仅是在你的上面应用自己的高亮,留下一个蓝色的高亮。
您可以通过IB或代码来完成此操作。
2)子类化 NSTableView,并覆盖 drawRow。
这将将所选行的背景颜色设置为主要(活动窗口)和次要(非活动)。
- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
    NSColor* bgColor = Nil;

    if (self == [[self window] firstResponder] && [[self window] isMainWindow] && [[self window] isKeyWindow])
    {
        bgColor = [NSColor colorWithCalibratedWhite:0.300 alpha:1.000];
    }
    else
    {
        bgColor = [NSColor colorWithCalibratedWhite:0.800 alpha:1.000];
    }

    NSIndexSet* selectedRowIndexes = [self selectedRowIndexes];
    if ([selectedRowIndexes containsIndex:row])
    {
        [bgColor setFill];
        NSRectFill([self rectOfRow:row]);
    }
    [super drawRow:row clipRect:clipRect];
}

3) 实现一个NSTableViewDelegate,将其附加到你的NSTableView上,并实现willDisplayCell方法。

这将允许你在选择/取消选择行时更改文本行的文本颜色,以防止选择颜色使文本难以阅读。

- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
    // check if it is a textfield cell
    if ([aCell isKindOfClass:[NSTextFieldCell class]])
    {
        NSTextFieldCell* tCell = (NSTextFieldCell*)aCell;
        // check if it is selected
        if ([[aTableView selectedRowIndexes] containsIndex:rowIndex])
        {
            tCell.textColor = [NSColor whiteColor];
        }
        else
        {
            tCell.textColor = [NSColor blackColor];
        }
    }
}

完成了。


9
有道理。如果我们可以添加所有这些代码并且一直试图弄清楚它,为什么苹果要像在iOS的UITableView中那样向NStableView添加一个更改所选行颜色的选项呢?哎,Cocoa团队需要紧急会晤Cocoa Touch团队。 - Duck
如果您能提供一个Swift解决方案,那就太好了,我无法适应您的代码。 - ixany
奇怪的是,对于我来说DrawRow从未被调用...在Xamarin上。 - tofutim

2
- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView
{

    if ([self isHighlighted])
    {
        NSRect bgFrame = frame;
        [[NSColor redColor] set];  
        NSRectFill(bgFrame);

    }
}

我在自定义的单元格文件中使用这段代码来处理高度:


也可以工作,但它不会覆盖 highlightSelectionInClipRect 的功能吗? - Artem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接