如何正确使用自定义视图?

Jus*_*tin 0 cocoa objective-c nsview

我一直在尝试制作一个简单的绘图程序.最近,我已经想出为此目的在自定义视图中绘制形状.我的问题是我必须在一个时间点绘制所有内容.我不知道这是否真的有意义,但在我看来它只调用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
Run Code Online (Sandbox Code Playgroud)

然后,在.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];

}
Run Code Online (Sandbox Code Playgroud)

@结束

在启动时,它会在左下角绘制一个矩形,就像它应该的那样.问题是,该drawRect方法仅在启动时调用.无论我做什么,它都不会开火.

编辑:我刚刚更新了代码.我希望它有所帮助.

第二次编辑:我真的简化了代码.我希望这会有所帮助.

Jon*_*ess 6

简答: 当您的视图状态发生更改以使其绘制方式不同时,您需要调用 - [NSView setNeedsDisplay:].这将导致您的视图的drawRect:方法在不久的将来被调用.你永远不应该打电话给drawRect:你自己.这是一个代表你调用的回调.

当您的应用程序中发生导致您想要更改绘图的事件时,请捕获实例变量中发生的事件的状态,调用setNeedsDisplay:然后在调用drawRect:时执行新绘图.

长答案: 在Cocoa中,窗口绘图是使用拉/无效模型完成的.这意味着窗口会知道它是否需要绘制,当它认为需要绘制时,它会在每个事件循环中绘制一次.

如果您不熟悉事件循环,可以在Wikipedia上阅读它们

在应用程序的顶层,您可以想象Cocoa正在这样做:

while (1) {
   NSArray *events = [self waitForEvents];
   [self doEvents:events];
}
Run Code Online (Sandbox Code Playgroud)

事件是鼠标移动,键盘按下,定时器关闭等.

NSView有一个方法 - [NSView setNeedsDisplay:].它需要一个布尔参数.当调用该方法时,窗口使该视图的绘图区域无效,并调度事件以供将来进行重绘 - 但仅限于未安排预先存在的重绘事件.

当runloop下次旋转时,将重新绘制使用setNeedsDisplay:标记的视图.这意味着您可以连续多次调用setNeedsDisplay:并且绘图将被批量调用到将来的一次drawRect调用:这对于性能原因很重要,这意味着您可以在一个方法中多次更改视图的框架,但只能在最终位置绘制一次.