extra redrawing with [self setBounds:] in drawRect:

  • extra redrawing with [self setBounds:] in drawRect:

    In my custom view, I set the bounds in my drawRect:
    method before drawing. This is so that while the user
    is resizing the window, the content stretches with the
    view. I then added some code to draw a selection
    rectangle as the user drags across the image.

    Somehow this selection rectangle code triggers random
    extra redrawing. As soon as I start dragging things go
    weird. Dragging itself causes the whole view to
    flicker, instead of just the invalidated portions.
    Even when done dragging, the view keeps getting pairs
    of drawRect calls *way* more often than normal: any
    time the window is brought to front, any time the
    window as a whole is moved, etc. If I resize the
    window the spurious events stop, until I drag within
    the view again.

    If I call setBounds: only if ([self inLiveResize]),
    then the problem goes away and the view only gets
    asked to redraw when dragging or window resizing
    invalidates it. But by my understanding, setBounds:
    shouldn't cause extra redrawing in the first place, so
    I don't think I've gotten to the root of the problem.

    Is it kosher to call [self setBounds:] in drawRect:?
    Why would a combination of setNeedsDisplayInRect: in
    an event responder and setBounds: in the draw code
    lead to the view getting extra drawRect: calls even
    when the event responders are done being used?

    thanks,
    -natevw

    Here's the relevant code (critique of any aspect
    appreciated as well):

    @interface CTPrototypeMapView : NSView {
    @private
    NSArray* polygons;
    BOOL dragging;
    NSPoint startingDragLocation;
    NSPoint currentDragLocation;
    }

    @end

    NSRect CTMakeRectFromPoints(NSPoint a, NSPoint b) {
    CGFloat origin_x, origin_y;
    CGFloat width, height;
    if (a.x < b.x) {
      origin_x = a.x;
      width = b.x - a.x;
    } else {
      origin_x = b.x;
      width = a.x - b.x;
    }
    if (a.y < b.y) {
      origin_y = a.y;
      height = b.y - a.y;
    } else {
      origin_y = b.y;
      height = a.y - b.y;
    }
    return NSMakeRect(origin_x, origin_y, width, height);
    }

    @implementation CTPrototypeMapView

    - (void)invalidateCurrentDragArea {
    NSRect dragRect =
    CTMakeRectFromPoints(startingDragLocation,
    currentDragLocation);
    //NSRect marredRect = NSInsetRect(dragRect, -0.2,
    -0.2);    // stroke extends a bit beyond passed rectangle
    NSRect marredRect = dragRect;
    [self setNeedsDisplayInRect: marredRect];
    }

    - (void)drawRect:(NSRect)rect {
    [self setBounds:NSMakeRect(-180, -90, 360, 180)];

    // ...draw a bunch of shapes...

    if (dragging) {
      NSRect dragRectangle =
    CTMakeRectFromPoints(startingDragLocation,
    currentDragLocation);
      NSBezierPath* shapeForDrag = [NSBezierPath
    bezierPathWithRoundedRect:dragRectangle xRadius:4
    yRadius:4];
      [shapeForDrag setLineWidth:0.2];
      [shapeForDrag stroke];
    }
    }

    - (void)dragTo:(NSPoint)location {
    [self invalidateCurrentDragArea];
    currentDragLocation = location;
    [self invalidateCurrentDragArea];
    }

    - (void)mouseDown:(NSEvent*)event {
    dragging = YES;
    NSPoint event_coordinates = [event locationInWindow];
    startingDragLocation = [self
    convertPoint:event_coordinates fromView:nil];
    }

    - (void)mouseDragged:(NSEvent*)event {
    if (!dragging) return;
    NSPoint event_coordinates = [event locationInWindow];
    NSPoint newDragLocation = [self
    convertPoint:event_coordinates fromView:nil];
    [self dragTo:newDragLocation];
    }

    - (void)mouseUp:(NSEvent*)event {
    dragging = NO;
    [self invalidateCurrentDragArea];
    }

    @end

          ____________________________________________________________________________________
    ¡Capacidad ilimitada de almacenamiento en tu correo!
    No te preocupes más por el espacio de tu cuenta con Correo Yahoo!:
    http://correo.espanol.yahoo.com/
  • On Jan 28, 2008, at 8:43 PM, Nathan Vander Wilt wrote:

    > extra redrawing with [self setBounds:] in drawRect:
    >
    >
    > In my custom view, I set the bounds in my drawRect:
    > method before drawing. This is so that while the user
    > is resizing the window, the content stretches with the
    > view.

    [...]

    > Somehow this selection rectangle code triggers random
    > extra redrawing.

    It is unclear why you need to resize your view inside of -drawRect:.
    This is surely the root cause of your problem.

    If your view cannot be automatically resized when the window is
    resized via springs and struts, use the appropriate mechanism to
    adjust the view's frame.

    Resizing the view inside of -drawRect: doesn't sound like good design.
    And it isn't terribly surprising that it might confuse the code which
    tracks view invalidation.

    Jim
  • >> In my custom view, I set the bounds in my drawRect:
    >> method before drawing. This is so that while the
    user
    >> is resizing the window, the content stretches with
    the
    >> view.
    [...]
    >> Somehow this selection rectangle code triggers
    random
    >> extra redrawing.

    > It is unclear why you need to resize your view
    inside of -drawRect:.
    > This is surely the root cause of your problem.

    I am not resizing the view programmatically via
    -setFrame:, I am setting the internal coordinate
    system via -setBounds. If I understand correctly, all
    this should do is set the transformation matrix. Yet
    somehow between doing that and invalidating a part of
    the view, I end up getting tons of extra redraw
    requests.

          ____________________________________________________________________________________
    ¡Capacidad ilimitada de almacenamiento en tu correo!
    No te preocupes más por el espacio de tu cuenta con Correo Yahoo!:
    http://correo.espanol.yahoo.com/