NSOutlineView setNeedsDisplayInRect вызывает ошибку - PullRequest
2 голосов
/ 13 июня 2011

У меня есть NSOutlineView, который использует собственный подкласс NSCell для рисования NSProgressIndicator.Каждый 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 останавливаются и запускаются в классе drawInteriorWithFrame:inView: моего 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.Я вручную проверил NSRect, возвращенный моим вызовом rectOfRow, и могу подтвердить, что значение верное.

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

self.progressIndicator = nil;

Когда NSOutlineView завершает обновление всех своих элементов, он запускает вызов reloadData:.Это единственное, что, по-видимому, надежно обновляет все рассматриваемые ячейки, в конечном итоге удаляя NSProgressIndicators.

Что я здесь не так делаю?

1 Ответ

0 голосов
/ 27 июня 2011

Плохо практиковаться, связываться с иерархиями представления, пока все прорисовывается.Лучше всего использовать NSCell версию NSProgressIndicator, но AppKit не имеет такой вещи.Решение, описанное в ответе Даниэля Ялкута на похожий вопрос, вероятно, является самым быстрым путем к тому, что вы хотите.Вот основная идея:

Вместо того, чтобы использовать переменную refreshing для переключения путей во время рисования, следите за состоянием refreshing ваших предметов.Когда это станет правдой, добавьте NSProgressIndicator в качестве подпредставления вашего NSOutlineView в позиции элемента с учетом frameOfCellAtColumn:row: (может быть удобно установить столбец для индикаторов прогресса в крайнем правом углу).Когда он становится ложным, удалите соответствующий индикатор прогресса.Вы также должны быть уверены, что установите соответствующие флажки автоматического изменения размера для этих индикаторов прогресса, чтобы они перемещались по мере изменения размера схемы.

...