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];
    }
}   

drawInteriorWithFrame:inView:NSProgressIndicatorインスタンスの項目は、次のように、NSCellのクラス内で停止および開始されます。

- (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のバージョンを使用するのが最善ですがNSProgressIndicatorAppKitそのようなことはありません。同様の質問に対するDanielJalkutの回答で説明されている解決策は、おそらくあなたが望むものへの最速の道です。基本的な考え方は次のとおりです。

refreshing変数を使用して描画中にパスを切り替えるのではなく、アイテムのrefreshing状態を観察してください。それが真になったら、指定されたアイテムの位置NSProgressIndicatorに自分のサブビューとしてを追加します(右端に進行状況インジケーターの列を設定すると便利な場合があります)。falseになったら、対応する進行状況インジケーターを削除します。また、これらの進行状況インジケーターに自動サイズ設定フラグを適切に設定して、アウトラインビューのサイズが変更されたときに移動するようにする必要があります。NSOutlineViewframeOfCellAtColumn:row:

于 2011-06-27T19:51:08.153 に答える