2014-11-27 1 views
2

Мне нужно перерисовать часть некоторого NSView.NSView setNeedDisplay: rect вызывает перерисовку большей площади, чем необходимо

- (IBAction)onUpdateView:(id)sender 
{ 
    NSRect updatedRect = ... // Redraw updated area only. 
    [self.view setNeedsDisplayInRect:updatedRect]; 
} 

Когда я использую это простое и очевидное решение, Quartz Debug подчеркивает перерисовки гораздо больших областей - до всей площади зрения.

Я заметил, что если вызов [NSView setNeedsDisplayInRect] откладывается до следующего цикла цикла выполнения, или я просто сделать [runloop runUntilDate: +0], проблема исчезает:

- (IBAction)onUpdate:(id)sender 
{ 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [self setNeedsDisplayInRect:updatedRect]; 
    }); 
} 

или

- (IBAction)onUpdateAndRunLoop:(id)sender 
{ 
    [self.view setNeedsDisplayInRect:updatedRect]; 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]]; // EEW 
} 

но если setNeedsDisplayInRect вызывается в обработчике MouseDown, он работает без всего этого повозка, запряженная волами:

-(void)mouseUp:(NSEvent*)event 
{ 
    NSPoint p = [self convertPoint:[event locationInWindow] fromView:nil]; 

    int size = 100; 
    [self setNeedsDisplayInRect:NSMakeRect(p.x-size/2, p.y-size/2, size, size)]; 
} 

Что происходит и что делать?

Изолированный Xcode проект для этой проблемы здесь: http://beta.kalinsky.ru/wtf/testRedraw.tar.gz

+0

Имеет ли этот вид вы хотите перерисовать собственный метод drawRect? Если так, вы рисуете все там или вы уважаете dirtyRect и только перерисовываете материал, который находится в этом прямоугольнике? Или, может быть, это мнение обрезается, а также выводит его внеэкранный контент? – HAS

+0

@ ХАС: Конечно, это было мое первое подозрение. Метод drawRect в прикрепленном проекте буквально "[NSBezierPath fillRect: dirtyRect];" –

+0

Вы нашли лучшее объяснение, чем тот, который я дал ниже в ответ и комментарии? При рисовании текст и прозрачность влияют на большую производительность. –

ответ

2

Что вы так уверены, что это нежелательное поведение? Поведение, которое я наблюдаю под Quartz Debugger, показывает, что, когда я нажимаю кнопку «Обновить», мигает пересечение прямоугольника кнопки щелчка и пропущенного dirtyRect. Это ожидается, так как система объединила весь необходимый чертеж в пределах одного и того же прохода runloop (с помощью мыши вверх) для повышения эффективности.

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

Надеюсь, это поможет.

+0

Звучит разумно, но я не уверен, что это поведение желательно и правильно. Я попробовал еще один эксперимент: я поместил текстовую метку в один угол главного окна и начал рисовать смешные квадраты на противоположном. В этом случае QuartzDebug мигает всей областью 2560x1600, а WindowServer использует до ~ 50% CPU: http://beta.kalinsky.ru/wtf/deferred_vs_direct.png (график показывает использование CPU процессом WindowServer) –

+1

Это кажется странным , Что произойдет, если вы переопределите свой собственный вид -isOpaque, чтобы вернуть ДА? –

+0

Ничего себе, это полностью устраняло проблему в прилагаемом xcodeproj :-) http://beta.kalinsky.ru/wtf/opaque_vs_transparent.png, источник: http://beta.kalinsky.ru/wtf/testRedraw-opaque.tar .gz Но мне непонятно, почему система решает перекрасить всю область, даже если под ней нет представлений. –

Смежные вопросы