3

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

这与WWDC 2011 会话View Based NSTableView Basic to Advanced中的HoverTableView 示例几乎相同。您可以在右侧帐户类型表格视图的邮件、联系人和日历系统首选项窗格中看到该行为。

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

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

4

2 回答 2

2

我认为这个问题的答案是“你不能”,即updateTrackingAreasforNSTableRowView在快速滚动NSTableView中,在运行循环上的发生速度不够快,无法依赖它来确定指针是否在行视图内。再次,请参阅HoverTableView 示例代码以了解在何处updateTrackingAreas使用。

我确实认为我有一个合适的解决方案。我注意到 Mac 版 Twitter ( RIP ) 的鼠标悬停视图随着鼠标移动而出现,但在滚动时消失,这与我希望实现的鼠标悬停高亮非常相似。

为了执行此操作,我基本上让我的自定义NSTableRowView有一个委托(我的自定义NSTableViewController),它会询问它是否应该在悬停时突出显示。NSScrollView我为我使用了一个习惯NSTableView并打电话给

    [self.contentView setPostsBoundsChangedNotifications:YES];

并使其awakeFromNib注册self为该通知的观察员。在收到该通知时,这意味着我的表格视图正在滚动,我的自定义NSScrollView将一条消息转发到我的NSTableViewController.

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

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

于 2012-09-28T11:08:46.970 回答
1

此处描述了此问题的解决方案:mouseExited is not called when mouse leave 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];
}
于 2014-05-29T09:07:27.217 回答