clearing (not erasing) when drawing from a thread

  • Apologies in advance if this has already been answered. While
    questions similar to mine have been posted, I wasn't able to locate
    actual  working answers.

    On Tiger, when repeatedly drawing to a view from a thread, how do I
    "clear out" what I drew before? NSEraseRect() won't work as it erases
    to white. NSRectFillUsingOperation() with [NSColor clearColor] results
    in a black rect. Tricks like erasing to the background color won't
    work for me as there is no "the" background color (my drawing will be
    placed over an arbitrary and possibly changing background).

    More details:

    I'm trying to implement a busy indicator, much like the indeterminate
    version of NSProgressIndicator. I have a sequence of images that I
    draw from a thread thusly (this is a method of my NSView subclass and
    is called off the main thread):

    - (void) animatorThreadWithImages:(NSArray*)images
    {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc]init];

        while (animate)
        {
            if ([self lockFocusIfCanDraw])
            {
                NSImage* tiffImage = [images
    objectAtIndex:frameNumber]; // This is an image with transparency.
                [tiffImage drawAtPoint:NSMakePoint(0, 0)
    fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];

                [[NSGraphicsContext currentContext] flushGraphics];
                [self unlockFocus];
            }

            frameNumber = (frameNumber+1)%sFrameCount;

            [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:
    0.05]];
        }

        animating = NO;
        [pool release];
    }

    The problem is that successive frames of my image get composited on
    top of each other. Note that my busy indicator will be positioned over
    an arbitrary display, so tricks like erasing to the "background" color
    won't work.

    _murat
  • On 25 Nov 2007, at 23:57, m wrote:

    > Apologies in advance if this has already been answered. While
    > questions similar to mine have been posted, I wasn't able to locate
    > actual  working answers.
    >
    > On Tiger, when repeatedly drawing to a view from a thread, how do I
    > "clear out" what I drew before? NSEraseRect() won't work as it
    > erases to white. NSRectFillUsingOperation() with [NSColor
    > clearColor] results in a black rect. Tricks like erasing to the
    > background color won't work for me as there is no "the" background
    > color (my drawing will be placed over an arbitrary and possibly
    > changing background).

    AFAIK you'd have to force the underlying views to refresh that part of
    the display.  That would be bad, because it would result in their
    drawing code running from a thread, and not all views will be thread-
    safe.

    Layer-backed views would offer one way out if you were on Leopard, I
    think, because they're composited together rather than simply drawn in
    order into the same buffer.  If you're on Tiger, I think you're either
    going to have to use a child window, or manually save the background,
    and draw that as the first step in your code.  But the latter won't
    work if the background is animating, so if that's a possibility then
    you probably want to use a child window.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • On Sun, 25 Nov 2007 15:57:10 -0800, m <m0987...> said:
    > [tiffImage drawAtPoint:NSMakePoint(0, 0)
    > fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
    >
    > The problem is that successive frames of my image get composited on
    > top of each other

    Possibly this has something to do with what NSCompositeSourceOver means. It
    might help to experiment with other options...

    > (my drawing will be placed over an arbitrary and possibly changing background)

    But you are still the one drawing that background, right? So if necessary
    you *could* draw it again in the area where the image is to go, right?

    Just some things to think about - These are the sorts of considerations that
    have led me to solutions of similar problems in the past... m.

    --
    matt neuburg, phd = <matt...>, <http://www.tidbits.com/matt/>
    A fool + a tool + an autorelease pool = cool!
    One of the 2007 MacTech Top 25: <http://tinyurl.com/2rh4pf>
    AppleScript: the Definitive Guide - Second Edition!
    <http://www.amazon.com/gp/product/0596102119>
  • Having thought this over, and reflecting on what is probably going on
    in the normal case of drawing, I have concluded that what I'm after
    is not generally possible.

    Here's my reasoning; I'd be happy to be proved wrong, but here goes:

    Loosely, when I'm drawing to a window from a thread, I am asking to
    have my image to be composited onto a bitmap that is shared by all
    views in the window.

    In Cocoa's normal drawing, the entire view stack is re-composited,
    one view at a time. The effect of having my superviews composited
    onto the shared bitmap before I draw is that what ever I drew before
    has been effectively erased.

    When drawing from a thread, I don't have the benefit of my superviews
    clearing out what I drew before, and calling  drawRect: on all my
    superviews is obviously not a solution.

    The only alternative I can think of is to periodically grab an image
    of the composited view stack (minus my view) on the main thread, and
    feed it to my thread, then from my thread composite my stuff on top
    of the image then draw the result.

    _murat

    On Nov 26, 2007, at 7:58 AM, Matt Neuburg wrote:

    > On Sun, 25 Nov 2007 15:57:10 -0800, m <m0987...> said:
    >> [tiffImage drawAtPoint:NSMakePoint(0, 0)
    >> fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
    >>
    >> The problem is that successive frames of my image get composited on
    >> top of each other
    >
    > Possibly this has something to do with what NSCompositeSourceOver
    > means. It
    > might help to experiment with other options...
    >
    >> (my drawing will be placed over an arbitrary and possibly changing
    >> background)
    >
    > But you are still the one drawing that background, right? So if
    > necessary
    > you *could* draw it again in the area where the image is to go, right?
    >
    > Just some things to think about - These are the sorts of
    > considerations that
    > have led me to solutions of similar problems in the past... m.
  • Oops. That's what I get for reading messages in the wrong order. Yes,
    I had already come to the conclusions you outlined.

    _murat

    On Nov 26, 2007, at 2:32 AM, Alastair Houghton wrote:

    > On 25 Nov 2007, at 23:57, m wrote:
    >
    >> Apologies in advance if this has already been answered. While
    >> questions similar to mine have been posted, I wasn't able to
    >> locate actual  working answers.
    >>
    >> On Tiger, when repeatedly drawing to a view from a thread, how do
    >> I "clear out" what I drew before? NSEraseRect() won't work as it
    >> erases to white. NSRectFillUsingOperation() with [NSColor
    >> clearColor] results in a black rect. Tricks like erasing to the
    >> background color won't work for me as there is no "the" background
    >> color (my drawing will be placed over an arbitrary and possibly
    >> changing background).
    >
    > AFAIK you'd have to force the underlying views to refresh that part
    > of the display.  That would be bad, because it would result in
    > their drawing code running from a thread, and not all views will be
    > thread-safe.
    >
    > Layer-backed views would offer one way out if you were on Leopard,
    > I think, because they're composited together rather than simply
    > drawn in order into the same buffer.  If you're on Tiger, I think
    > you're either going to have to use a child window, or manually save
    > the background, and draw that as the first step in your code.  But
    > the latter won't work if the background is animating, so if that's
    > a possibility then you probably want to use a child window.
    >
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today