2

我有一个使用自定义 NSCell 子类来绘制 NSProgressIndicator 的 NSOutlineView。每个 NSCell 都有一个refreshing由 NSOutlineView 委托方法设置的属性willDisplayCell:forItem:,如下所示:

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    cell.refreshing = item.refreshing;
}

每个项目实例都包含一个 NSProgressIndicator,它的启动和停止取决于该特定项目是否正在刷新。

- (NSProgressIndicator *)startProgressIndicator
{
    if(!self.progressIndicator)
    {
        self.progressIndicator = [[[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 16.0f, 16.0f)] autorelease];
        [self.progressIndicator setControlSize:NSSmallControlSize];
        [self.progressIndicator setStyle:NSProgressIndicatorSpinningStyle];
        [self.progressIndicator setDisplayedWhenStopped:YES];
        [self.progressIndicator setUsesThreadedAnimation:YES];
        [self.progressIndicator startAnimation:self];
    }

    return self.progressIndicator;
}
- (void)stopProgressIndicator
{
    if(self.progressIndicator != nil)
    {
        NSInteger row = [sourceList rowForItem:self];

        [self.progressIndicator setDisplayedWhenStopped:NO];
        [self.progressIndicator stopAnimation:self];
        [[self.progressIndicator superview] setNeedsDisplayInRect:[sourceList rectOfRow:row]];
        [self.progressIndicator removeFromSuperviewWithoutNeedingDisplay];

        self.progressIndicator = nil;
    }

    for(ProjectListItem *node in self.children)
    {
        [node stopProgressIndicator];
    }
}   

项目 NSProgressIndicator 实例在我的 NSCelldrawInteriorWithFrame:inView:类中停止和启动,如下所示:

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    if(self.refreshing)
    {
        NSProgressIndicator *progressIndicator = [item progressIndicator];
        if (!progressIndicator)
        {
            progressIndicator = [item startProgressIndicator];
        }

        // Set the progress indicators frame here ...

        if ([progressIndicator superview] != controlView)
            [controlView addSubview:progressIndicator];

        if (!NSEqualRects([progressIndicator frame], progressIndicatorFrame)) {
            [progressIndicator setFrame:progressIndicatorFrame];
        }
    }
    else
    {
        [item stopProgressIndicator];
    }

    [super drawInteriorWithFrame:cellFrame inView:controlView];
}

我遇到的问题是,尽管正确告知 NSProgressIndicators 停止,但对 stopProgressIndicator 的调用无效。这是未能触发刷新相关 NSOutlineView 行的代码。我已经手动检查了调用 rectOfRow 返回的 NSRect 并且可以确认该值是正确的。

[self.progressIndicator setDisplayedWhenStopped:NO];
[self.progressIndicator stopAnimation:self];
[[self.progressIndicator superview] setNeedsDisplayInRect:[sourceList rectOfRow:row]];
[self.progressIndicator removeFromSuperviewWithoutNeedingDisplay];

self.progressIndicator = nil;

当 NSOutlineView 完成刷新它的所有项目时,它会触发一个reloadData:调用。这是唯一似乎可靠地更新所有有问题的单元格的东西,最终删除了 NSProgressIndicators。

我在这里做错了什么?

4

1 回答 1

0

在绘制事物时弄乱视图层次结构是一种不好的做法。最好的办法是使用 的NSCell版本NSProgressIndicator,但AppKit没有这样的东西。Daniel Jalkut 对类似问题的回答中描述的解决方案可能是您想要的最快途径。这是基本思想:

refreshing与其在绘图期间使用变量切换路径,不如观察项目的refreshing状态。当它变为真时,在给定项目的位置添加一个NSProgressIndicator作为您的子视图(在最右侧为进度指示器设置一列会很方便)。当它变为 false 时,移除相应的进度指示器。您还需要确保在这些进度指示器上适当地设置自动调整大小标志,以便它们在大纲视图调整大小时四处移动。NSOutlineViewframeOfCellAtColumn:row:

于 2011-06-27T19:51:08.153 回答