如何制作NSTableRowView drawBackgroundInRect,基于trackingAreas,在滚动时更新得足够快?

时间:2012-09-21 13:24:47

标签: cocoa nstableview

我正在使用基于视图的NSTableView和自定义NSTableRowView。我想通过drawBackgroundInRect使用自定义行背景绘图,基于使用trackingAreas的鼠标位置。目标是为鼠标当前悬停的未选择行绘制自定义背景。

这几乎与WWDC 2011会话中的HoverTableView example相同基于视图的NSTableView Basic到高级。您可以在 Mail,Contacts&日历系统偏好设置窗格右侧的帐户类型表格视图。

与示例不同,我的表视图中有数千行。除非我快速滚动表格视图(例如,通过触控板进行双指轻弹),否则一切都按照示例中的方式工作。在这种情况下,似乎没有足够快地调用updateTrackingAreas。在鼠标下滚动的行会突出显示,但不会通知鼠标离开其跟踪区域,因此会保持突出显示。结果是显示鼠标悬停突出显示的多行,并且由于重用队列,这些将滚动到表视图的一端并重新出现在另一端(当然,不同的数据)仍然突出显示,就好像它们被重叠一样。滚动慢慢消除了这个问题;但考虑到我希望滚动成千上万行,慢慢滚动并不是预期的用户行为。

我尝试过NSTrackingAreaOptions的各种组合无济于事,现在我很难过。有任何关于解决这个问题的建议将不胜感激。

2 个答案:

答案 0 :(得分:2)

我认为这个问题的答案是“你不能”,即快速滚动updateTrackingAreasNSTableRowView的{​​{1}}在运行循环中不能足够快地发生依靠它来确定指针是否在行视图内。再次,请参阅the HoverTableView example code,了解NSTableView的使用位置。

我认为我有一个合适的解决方案。我注意到Twitter for Mac(RIP)具有鼠标移动视图,鼠标移动但在滚动时消失,非常类似于我希望实现的鼠标移动高光。

为了执行此操作,我基本上使我的自定义updateTrackingAreas有一个委托(我的自定义NSTableRowView),它会询问是否应该在悬停时突出显示。我为NSTableViewController使用了自定义NSScrollView并将其称为

NSTableView

[self.contentView setPostsBoundsChangedNotifications:YES]; 中,并将其注册为awakeFromNib作为该通知的观察者。收到该通知后,我的自定义self会将消息转发给我的NSScrollView

当我的NSTableViewController收到表视图正在滚动的消息时,它会在鼠标悬停时禁用突出显示,如果还没有从先前通知运行的有效计时器,则会触发一个短计时器以重新启用突出显示鼠标悬停一旦滚动停止。作为额外的预防措施,在鼠标悬停时启用和禁用突出显示之间的状态转换时,我的NSTableViewController使用NSTableViewController清除enumerateAvailableRowViewsUsingBlock每个行视图。

不确定这是否是最好的方法,但它可以达到我想要的效果。

答案 1 :(得分:1)

此问题的解决方案如下所述:mouseExited isn't called when mouse leaves trackingArea while scrolling

我的updateTrackingAreas方法现在看起来像:

- (void)updateTrackingAreas {
    if (trackingArea)
        [self removeTrackingArea:trackingArea];

    [trackingArea release];

    trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
                                                options:NSTrackingInVisibleRect |
                                                        NSTrackingActiveAlways |
                                                        NSTrackingMouseEnteredAndExited
                                                  owner:self
                                               userInfo:nil];

    [self addTrackingArea:trackingArea];

    NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
    mouseLocation = [self convertPoint: mouseLocation fromView: nil];

    if (NSPointInRect(mouseLocation, [self bounds]))
        [self mouseEntered:nil];
    else
        [self mouseExited:nil];

    [super updateTrackingAreas];
}