简体   繁体   中英

How to update a section of an NSView without redrawing the whole view

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

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.

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];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM