Как правильно использовать пользовательский вид? - PullRequest
0 голосов
/ 13 апреля 2011

Я пытался сделать простую программу для рисования.Недавно я решил нарисовать фигуры в специальном представлении для этой цели.Моя проблема в том, что я должен нарисовать все в один момент времени.Я не знаю, имеет ли это смысл, но мне кажется, что он вызывает метод drawRect только один раз, при этом "один раз" при запуске.

Вот мой код:

Заголовочный файл.

NSBezierPath *thePath;
NSColor *theColor;
NSTimer *updateTimer;
NSPoint *mousePoint;
int x = 0;
int y = 0;

@interface test : NSView {
    IBOutlet NSView *myView;

}

@property (readwrite) NSPoint mousePoint;

@end

Затем реализация в файле .m.

@implementation test

@synthesize mousePoint;

- (void) mouseDown:(NSEvent*)someEvent {         
    CGEventRef ourEvent = CGEventCreate(NULL);
    mousePoint = CGEventGetLocation(ourEvent);
    NSLog(@"Location: x= %f, y = %f", (float)mousePoint.x, (float)mousePoint.y);
    thePath = [NSBezierPath bezierPathWithRect:NSMakeRect(mousePoint.x, mousePoint.y, 10, 10)];
    theColor = [NSColor blackColor];  

} 

- (void) mouseDragged:(NSEvent *)someEvent {
    mousePoint = [someEvent locationInWindow];
    NSLog(@"Location: x= %f, y = %f", (float)mousePoint.x, (float)mousePoint.y);
    x = mousePoint.x;
    y = mousePoint.y;
    [myView setNeedsDisplay:YES];

}

- (void) drawRect:(NSRect)rect; {
    NSLog(@"oisudfghio");
    thePath = [NSBezierPath bezierPathWithRect:NSMakeRect(x, y, 10, 10)];
    theColor = [NSColor blackColor];
    [theColor set];
    [thePath fill];

}

@ end

При запуске он рисует прямоугольникв левом нижнем углу, как и должно быть.Проблема в том, что метод drawRect вызывается только при запуске.Это просто не сработает, независимо от того, что я делаю.

РЕДАКТИРОВАТЬ: Я только что обновил код.Надеюсь, это поможет.

ВТОРОЕ РЕДАКТИРОВАНИЕ: Я действительно упростил код.Я надеюсь, что это поможет немного больше.

Ответы [ 2 ]

6 голосов
/ 13 апреля 2011

Краткий ответ: Когда состояние вашего представления изменяется так, что оно будет отображаться по-другому, вам нужно вызвать - [NSView setNeedsDisplay:]. Это приведет к вызову drawRect: метод вашего представления в ближайшем будущем. Вы никогда не должны вызывать drawRect: себя. Это обратный вызов, который вызывается от вашего имени.

Когда в вашем приложении происходят события, которые заставляют вас захотеть изменить свой чертеж, записать состояние о том, что произошло, в переменные экземпляра, вызвать setNeedsDisplay: и затем позже при вызове drawRect: создайте новый чертеж.

Длинный ответ: В Какао рисование окон выполняется с помощью модели извлечения / аннулирования. Это означает, что у окна есть представление о том, нужно ли ему рисовать, и когда оно думает, что ему нужно рисовать, оно рисует один раз за цикл событий.

Если вы не знакомы с циклами событий, вы можете прочитать о них в Wikipedia

На верхнем уровне приложения вы можете представить, что Cocoa делает это:

while (1) {
   NSArray *events = [self waitForEvents];
   [self doEvents:events];
}

Где события - это, например, движение мыши, нажатие клавиатуры и отключение таймеров.

NSView имеет метод - [NSView setNeedsDisplay:]. Он принимает логический параметр. Когда этот метод вызывается, окно лишает законной силы область рисования для этого вида и планирует событие на будущее, чтобы выполнить перерисовку - но только если не запланировано ранее существующее событие перерисовки.

Когда runloop вращается в следующий раз, представления, помеченные с помощью setNeedsDisplay: перерисовываются. Это означает, что вы можете вызывать setNeedsDisplay: несколько раз подряд и рисование будет объединено в один вызов drawRect: в будущем. Это важно с точки зрения производительности и означает, что вы можете делать такие вещи, как изменение фрейма вида несколько раз в одном методе, но он будет нарисован только один раз в конечном местоположении.

1 голос
/ 13 апреля 2011

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

Вместо жесткого кодирования всех значений, рассмотрите возможность использования переменных экземпляра для вещей, которые вы хотите изменить во время выполнения, например,цвет рисования и прямоугольник.Затем в вашем методе mouseDragged: отправьте представление (myView в вашем примере) сообщение setNeedsDisplay:.Если вы передадите YES в качестве аргумента, фреймворк вызовет для вас метод drawRect:.

...