2012-06-25 5 views
3

Я заметил странную проблему с моим приложением на основе какао в Mac OS X 10.7. По какой-то причине (не важно здесь) иногда мне приходится рисовать вне метода drawRect моего пользовательского представления.display vs. setNeedsDisplay

Мне нужно позвонить lockFocus/lockFocusIfCanDraw на мой взгляд, спросить текущий контекст, сделать фактический чертеж с семейством функций CGContext (CoreGrapchis), а в конце сделать CGContextFlush (я могу также очистить окно или использовать NSGraphicsContext класс для создания флеша).

Эта последовательность на самом деле такая же, как если бы я вызывал метод отображения NSView.

Проблема в том, что она в 3-4 раза медленнее, чем «естественный» способ (вызовите setNeedsDisplay или рисуйте из drawRect, когда Cocoa попросит вас сделать это). Я не могу просто вызвать, например, setNeedsDisplay для представления, мне нужна эта функция '-display-like'.

В примере теста (который использует таймер), для простоты, я вызываю -display (поскольку он вообще работает с тем же моим приложением) vs -setNeedsDisplay, и я могу видеть время '-display 'в 3-4 раза дольше, чем' -setNeedsDisplay '.

Вот пример моего класса CustomView (реализация):

#import <QuartzCore/QuartzCore.h> 

#import "CustomView.h" 

@implementation CustomView 
{ 
    CFTimeInterval startTime; 
    NSTimer *timer; 
    unsigned step; 
} 

- (id)initWithFrame:(NSRect)frame 
{ 
    return [super initWithFrame : frame]; 
} 

- (void)drawRect:(NSRect)dirtyRect 
{ 
    CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; 

    if(!timer) 
    { 
     CGContextSetRGBFillColor(ctx, 1., 1., 1., 1.); 
     CGContextFillRect(ctx, dirtyRect); 
    } 
    else 
    { 
     CGContextSetRGBFillColor(ctx, 0., 0., 0., 1.); 
     CGContextFillRect(ctx, CGRectMake(step * 1.5, 100, 2., 2.)); 
    } 
} 

- (void) mouseDown : (NSEvent *)theEvent 
{ 
    if (!timer) 
    { 
     startTime = CACurrentMediaTime(); 
     timer = [NSTimer scheduledTimerWithTimeInterval : 0.006 target : self selector : @selector(handleTimer:) userInfo : nil repeats : YES]; 
     step = 0; 
    } 
} 

- (void) handleTimer : (NSTimer *) dummy 
{ 
    if(step < 200) 
    { 
     ++step; 
#if 1 
     [self display]; 
#else 
     [self setNeedsDisplay : YES]; 
#endif 
    } 
    else 
    { 
     [timer invalidate]; 
     timer = nil; 
     NSLog(@"animation time is: %g", CACurrentMediaTime() - startTime); 
    } 
} 

@end 

Я думаю, что даже если CACurrentMediaTime не очень хорошая функция для моей цели, он все еще может показать разницу очевидного времени (и это легко уведомление без каких-либо измерений - дисплей очень медленный). Метод handleTimer имеет два раздела - если вы измените '1' на '0' в pp-директиве, вы можете попробовать оба варианта -display/-setNeedsDisplay. Итак, у меня есть, например, следующий результат:

-display: 3.32 s. (?)

-setNeedsDisplay: 1.2 s.

Я посмотрел на дерево звонков/время, проведенное с помощью приложения «Инструменты», но это не очень помогло мне.

Редактировать: Хмммм, я могу видеть сейчас: на самом деле, с представлением setNeedsDisplay не перерисовывается на каждом событии таймера!

ответ

0

Нет необходимости опускать функции CG в методе drawRect.

Этот код эквивалентен:

- (void)drawRect:(NSRect)dirtyRect 
{ 
    if(!timer) 
    { 
     [[NSColor whiteColor] set]; 
     NSRectFill(dirtyRect); 
    } 
    else 
    { 
     [[NSColor blackColor] set]; 
     NSRectFill(NSMakeRect(step * 1.5, 100.0, 2.0, 2.0)); 
    } 
} 

Что касается -display и -setNeedsDisplay, бывший делает рисунок произойдет сразу, последний устанавливает флаг, и каждый раз через цикл событий, если этот флаг true, окно отправит -display в рассматриваемое представление и очистит флаг.

Еще одна вещь: этот подход использования NSTimer для управления анимацией немного устарел. Вы должны прочитать документы в Core Animation, чтобы узнать, как это сделать.

+0

Итак, setNeedsDisplay устанавливает флаг, но позже AppKit (?) Может игнорировать этот флаг, и представление не перерисовывается? (примерно в 2/3 событий таймера) – user1479515

+0

У меня есть вызовы CoreGraphics здесь, поскольку в моем приложении Cocoa недостаточно для меня, и я использую CoreGrapchis.NSTimer здесь не важен, в моем реальном таймере приложения реализовано не мной, а по-другому, я даже не занимаюсь таймерными событиями, NSTimer здесь только для примитивной «анимации» и показывает, что с -display он медленный. – user1479515

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