views:

319

answers:

2

I have a NSView where I draw thousands of NSBezierPaths. I would like to highlight (change fill color) the a selected one on mousemoved event. At the moment I use in mouseMoved function the following command:

     [self setsetNeedsDisplay:YES];

that force a call to drawRect to redraw every path. I would like to redraw only the selected one. I tried to use addClip in drawRect function:

      NSBezierPath * path = ... //builds the path here
      [path addClip];
      [path fill];

but it seems that drawRect destroys all the other previously drawn paths and redraws only the one clipped.

Is it possible NOT to invalidate all the view when calling drawRect? I mean just to incrementally overwrite what was on the view before?

Thanks, Luca

+4  A: 

You should use [self setNeedsDisplayInRect:…]. Pass the NSRect you want invalidated, and that will be the area passed to the drawRect: call.

Inside drawRect:, check the area that was passed in and only perform the drawing necessary inside of that rectangle.

Also, you might want to look into using NSTrackingArea instead of mouseMoved: – these allow you to set up specific rectangles to trigger updates for.

Ciarán Walsh
Hi,ok, I can pass something like: [self setNeedsDisplayInRect: [path bounds]]... even if it is not very comfortable because I do not know how many paths there are on that NSRect... but I can try to rethink the function.Instead it is not very clear how I can exploit NSTrackingArea. At the moment I have already a trackingarea that covers the whole NSView, but I thought that the events generated are still sent to the mouseMoved function, aren't they?Thanks,Luca
luca castagnini
Your `mouseMoved:` method will be triggered with an `NSEvent` instance, and you send the event the `-trackingArea` message to get a reference to the `NSTrackingArea` instance which triggered it, and then ask it for the rect.
Ciarán Walsh
A: 

I think I solved in a faster way, as I do not know a priori which paths are present in a rectangle I want to avoid a loop through all the paths. Fortunately my paths do not change often, so I can cache all the paths in a NSImage. On mouseMoved event I set:

RefreshAfterMouseMoved = YES;

and in drawRect function I put something like:

if (RefreshAfterMouseMoved) {  
 [cacheImage drawAtPoint:zero fromRect:viewRect operation:1 
                       fraction:(CGFloat)1.0];
        //redraw only the hilighted path
}
else{
    if (cacheImage) [cacheImage release];   
    cacheImage = [[NSImage alloc] initWithSize: [self bounds].size ];
    [cacheImage lockFocus];
    // draw everything here
    [cacheImage unlockFocus];
    [cacheImage drawAtPoint:zero fromRect:viewRect operation:1 
                   fraction:(CGFloat)1.0];
}

This method can be combined with the above setNeedsDisplayInRect method putting in mousedMoved function:

   NSRect a, b, ab;
   a = [oldpath bounds];
   b = [newpath bounds];
   ab = NSUnionRect(a,b);
   RefreshAfterMouseMoved = YES;
   [self setNeedsDisplayInRect:ab];
luca castagnini