views:

262

answers:

1

I can draw many things using this :

NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"dummy2.png" ofType:nil];
UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
image = CGImageRetain(img.CGImage);

CGRect imageRect;

double x = 0;
double y = 0;

for (int k=0; k<someValue; k++) {
    x += k;
            y += k;

        imageRect.origin = CGPointMake(x, y);
        imageRect.size = CGSizeMake(25, 25);    
        CGContextDrawImage(UIGraphicsGetCurrentContext(), imageRect, image);
    }
}

CGImageRelease(img.CGImage);

So, it works, so, I put it into a command object's execute method. Then, I want to do similar thing, but this time, my execute method only do this:

NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"dummy2.png" ofType:nil];
UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
image = CGImageRetain(img.CGImage);

CGRect imageRect;

double x = inComingX;
double y = inComingY;

 imageRect.origin = CGPointMake(x, y);
        imageRect.size = CGSizeMake(25, 25);    
        CGContextDrawImage(UIGraphicsGetCurrentContext(), imageRect, image);

    CGImageRelease(img.CGImage);

This time, this is also a Command, and it is the execute method. But I take the for loop away. I will have another method that pass the inComingX , and inComingY into my Command object.

My Drawing method is simply execute the Cmd that passed in my drawingEngine:

-(void)drawInContext:(CGContextRef)context
{
    [self.cmdToBeExecuted execute];
}

I also have the assign method to assign the command,:

-(void)assignCmd:(Command* )cmd{
    self.cmdToBeExecuted = cmd;

}

And this is the way I called the drawingEngine

for(int k=0; k<5; k++){
    [self.drawingEngine assignCmd:[DrawingCmd setDrawingInformation:(10*k):0:@"dummy.png"]];
    [self.drawingEngine setNeedsDisplay];
}

It can draw, but the sad thing is it only draw the last one. Why? and how to fix it? I can draw all the things in my First code, but after I take the loop outside, and use the loop in last code, it just only draw the last one. Plz help

+4  A: 

That's because setNeedsDisplay does not actually call drawRect:. It simply schedules the view to be redrawn at the next "convenient" time, which is likely the next time, the application re-enters the run-loop. Since you overwrite the remembered command object on each call to the assignment function, by the time, the drawRect: is actually called, only the last assigned command is available and will be drawn.

A better way to do it would be: remember all commands to be drawn instead just the last one, say in an array, like:

@interface MyCanvas {
    ...
    NSMutableArray* commandList;
    ...
}

and add commands to that array instead of assigning a single command member:

-(void) addCommand:(Command*) cmd {
    [self.commandList addObject: cmd];
}

The commands should then be processed in your draw method

for( Command* cmd in self.commandList ) {

    [cmd execute ...];
}

Alternatively, you could define "complex" commands, which consist of more than a single drawing step.

(EDIT to answer the question in the comments): Your original code did work, because it does the work all in one place in a single invocation of the appropriate draw method. Your last code does not draw anything at all while it runs. It simply remembers (via command object) that something has to be done, and notifies the view, that it should redraw itself on the next convenient occasion. It is important to note, that setNeedsDisplay will not cause any repainting to be done directly. It simply marks the view as "dirty", which will be picked up by other code in the Cocoa run-time later.

There is another thing in your code which I find slightly suspicious: your method drawInContext: takes a context argument, which is simply ignored. Neither is it passed on to the execute method of you command object, nor is it installed as some kind of "current" drawing context in an instance variable or somesuch. If you expect the code in drawRect: (or the command's execute method) to actually use that context, you have to pass it on to whoever is supposed to use it.

Dirk
O...That's not the way I want, how can change my code to support drawing many stuff on the View? thz.... But one more question, why my First code can draw all the stuff?
Tattat