开发者

Erasing Cocoa Drawing done by NSRectFill?

开发者 https://www.devze.com 2023-03-16 23:59 出处:网络
I have an NSBox, ins开发者_高级运维ide of which I am drawing small rectangles, with NSRectFill(). My code for this looks like this:

I have an NSBox, ins开发者_高级运维ide of which I am drawing small rectangles, with NSRectFill(). My code for this looks like this:

for (int i = 0; i <= 100; i++){


    int x = (rand() % 640) + 20;
    int y = (rand() % 315) + 196;

    array[i] = NSMakeRect(x, y, 4, 4);
    NSRectFill(array[i]);
}

This for loop creates 100 randomly placed rectangles within the grid. What I have been trying to do is create a sort of animation, created by this code running over and over, creating an animation of randomly appearing rectangles, with this code:

for (int i = 0; i <= 10; i++) {      

   [self performSelector:@selector(executeFrame) withObject:nil afterDelay:(.05*i)];   

    }

The first for loop is the only thing inside the executeFrame function, by the way. So, what I need to do is to erase all the rectangles between frames, so the number of them stays the same and they look like they are moving. I tried doing this by just drawing the background again, by calling [myNsBox display]; before calling executeFrame, but that made it seem as though no rectangles were being drawn. Calling it after did the same thing, so did switching in setNeedsDisplay instead of display. I cannot figure this one out, any help would be appreciated.

By the way, an additional thing is that when I try to run my code for executing the frames, without trying to erase the rectangles in between, all that happens is that 100 more rectangles are drawn. Even if I have requested that 1000 be drawn, or 10,000. Then though, if I leave the window and come back to it (immediately, time is not a factor here), the page updates and the rectangles are there. I attempted to overcome that by with [box setNeedsDisplayInRect:array[i]]; which worked in a strange way, causing it to update every frame, but erasing portions of the rectangles. Any help in this would also be appreciated.


It sounds like you're drawing outside drawRect: . If that's the case, move your drawing code into a view's (the box's or some subview's) drawRect: method. Otherwise your drawing will get stomped on by the Cocoa drawing system like you're seeing. You'll also want to use timers or animations rather than loops to do the repeated drawing.


I recently wrote an example program for someone trying to do something similar with circles. The approach I took was to create an array of circle specifications and to draw them in drawRect. It works pretty well. Maybe it will help. If you want the whole project, you can download it from here

@implementation CircleView

@synthesize maxCircles, circleSize;

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        maxCircles = 1000;
        circles = [[NSMutableArray alloc] initWithCapacity:maxCircles];
    }
    return self;
}

- (void)dealloc {
    [circles release];
    [super dealloc];
}

- (void)drawRect:(NSRect)dirtyRect {
    NSArray *myCircles;
    @synchronized(circles) {
        myCircles = [circles copy];
    }
    NSRect bounds = [self bounds];
    NSRect circleBounds;
    for (NSDictionary *circleSpecs in myCircles) {
        NSColor *color = [circleSpecs objectForKey:colorKey];
        float size = [[circleSpecs objectForKey:sizeKey] floatValue];
        NSPoint origin = NSPointFromString([circleSpecs objectForKey:originKey]);
        circleBounds.size.width = size * bounds.size.width;
        circleBounds.size.height = size * bounds.size.height;
        circleBounds.origin.x = origin.x * bounds.size.width - (circleBounds.size.width / 2);
        circleBounds.origin.y = origin.y * bounds.size.height - (circleBounds.size.height / 2);
        NSBezierPath *drawingPath = [NSBezierPath bezierPath];
        [color set];
        [drawingPath appendBezierPathWithOvalInRect:circleBounds];
        [drawingPath fill];
    }
    [myCircles release];
}

#pragma mark Public Methods

-(void)makeMoreCircles:(BOOL)flag {
    if (flag) {
        circleTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(makeACircle:) userInfo:nil repeats:YES];
    }
    else {
        [circleTimer invalidate];
    }
}

-(void)makeACircle:(NSTimer*)theTimer {
    // Calculate a random color
    NSColor *color;        
    color = [NSColor colorWithCalibratedRed:(arc4random() % 255) / 255.0
                                      green:(arc4random() % 255) / 255.0
                                       blue:(arc4random() % 255) / 255.0
                                      alpha:(arc4random() % 255) / 255.0];
    //Calculate a random origin from 0 to 1
    NSPoint origin;
    origin.x = (double)arc4random() / (double)0xFFFFFFFF;
    origin.y = (double)arc4random() / (double)0xFFFFFFFF;
    NSDictionary *circleSpecs = [NSDictionary dictionaryWithObjectsAndKeys:color, colorKey, 
                                 [NSNumber numberWithFloat:circleSize], sizeKey, 
                                 NSStringFromPoint(origin), originKey,
                                 nil];
    @synchronized(circles) {
        [circles addObject:circleSpecs];
        if ([circles count] > maxCircles) {
            [circles removeObjectsInRange:NSMakeRange(0, [circles count] - maxCircles)];
        }
    }
    [self setNeedsDisplay:YES];
}

@end
0

精彩评论

暂无评论...
验证码 换一张
取 消