Thread: invalidating a rectangle

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    596

    invalidating a rectangle

    I have a device compatible bitmap where everything is drawn. After making some changes to the bitmap,
    I want to invalidate the area that was changed so that the corresponding client area will be updated.

    The client area might not be showing the entire area that was changed in the bitmap, though. Part of the
    area that was changed (in the bitmap) might be lying inside the client area and part of it might be lying
    outside of the client area.

    Do I need to make sure that the rectangle being invalidated resides within the client area?
    So do I need to get the intersection of the area I'm invalidating and the client area?

    Or does BeginPaint() make sure that the rectangle in the paint structure lies within the client area?
    Does InvalidateRect() and BeginPaint() give me a rectangle within the client area automatically?

    I am using the rectangle in the paint structure for the bitblt.

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Well... you could learn a lot here by experimenting... Invalidate the part you updated regardless of where it is and see what happens...

    Also make not of the WS_CLIPSIBLINGS and WS_CLIPCHILDREN window styles...

    Window Styles

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Something I noticed early on, when drawing directly in the client area, was that the drawing
    only occurred in the client area, even if trying to draw outside it.

    So I'm not sure how I would know if BeginPaint took care of it or the windows OS took care of
    of it, or it just happen to work by accident.

    But I'll try printing out the coordinates in the paint structure.

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Generally Windows does not let you colour outside the lines ...

  5. #5
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by megafiddle View Post
    I have a device compatible bitmap where everything is drawn. After making some changes to the bitmap,
    I want to invalidate the area that was changed so that the corresponding client area will be updated.

    The client area might not be showing the entire area that was changed in the bitmap, though. Part of the
    area that was changed (in the bitmap) might be lying inside the client area and part of it might be lying
    outside of the client area.
    This says your bitmap is larger than your apps client area.

    Your issue is that client area always starts at 0,0 for the left top but this point is not 0,0 on the bitmap (ie the draw area has an x,y offset from the top left of the bitmap).

    You can calc the offset by doing some conversions with ClientToScreen() and ScreenToClient() [this would work well if the bitmap is the same size as the whole screen]

    You will need to keep this offset updated on size and move msgs (or calc before calling for a paint).

    Quote Originally Posted by megafiddle View Post
    Do I need to make sure that the rectangle being invalidated resides within the client area?
    Not really, the drawing will not work properly in some cases however.

    Quote Originally Posted by megafiddle View Post
    So do I need to get the intersection of the area I'm invalidating and the client area?
    Sort of....

    Your issue is that if the paint is generatd outside your app, what area will it draw?

    Quote Originally Posted by megafiddle View Post
    Or does BeginPaint() make sure that the rectangle in the paint structure lies within the client area?
    No, but negative values in BitBlt() would probably not work as expected.

    Quote Originally Posted by megafiddle View Post
    Does InvalidateRect() and BeginPaint() give me a rectangle within the client area automatically?
    No and Yes...

    IIRC the rect can not be negative but I have not ried to see if the update rect can be bigger than the client area (I assume it can be). GetUpdateRect() and PtInRect() will let you test this.

    NOTES:
    Follow every InvalidateRect() with an UpdateWindow() (bypass OS queue and post to dialogs callback)

    This is why I advised you to create a back buffer (HDC and BITMAP) the same size as your app, adjusting it on size msgs.

    You can not draw outside the client area because the HDC in the paint struct is the same size as your apps client area (so any drawing outside this area is not copied to the screen image).

    In the OS msg queue WM_PAINT msgs are processed and concatinated into the smallest bounding rectangle. If there are other msgs in the queue (other than paint or timer) the paint msg is returned to the bottom of the OS queue (ie paint is the lowest priority, just above WM_TIMER) [which is why UpdateWindow() is so important for fast drawing]

    InvalidateRect() sets the update region in the paint msg (invalidates this area). This can be any area, if in doubt set the areat to the client rect.

    BeginPaint() gets and validates the area.
    Last edited by novacain; 10-04-2011 at 02:28 AM. Reason: clarity
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    In normal use, the entire graphics is visible in the client area. It's not too usable otherwise. This is just to handle the possibility
    that the client area has been reduced. It's possible that a mouse click in the client area could cause changes to occur that need
    updating, just as in the full size display. The bitmap image is completely updated. And then whatever part of the bitmap happens
    to visible in the client area gets updated too.

    I'm not using scoll bars, or any other means of moving the client "window" around over the full size bitmap image. The upper left
    corner of the client area always corresponds to the upper left corner of the bitmap.

    I tried displaying the coordinates in the PAINTSTRUCT, ps.rcPaint, each time WM_PAINT message comes in. But it's not working right.
    So I have to fix that. The values ought to change each time the window is enlarged or covered and then uncovered. They don't.

    And that's strange, because the bitblt, which uses the same coordinates does work.

  7. #7
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Post some code.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  8. #8
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    I disabled all the message handlers except WM_PAINT, WM_CLOSE, WM_DESTROY.
    So the program shouldn't be doing anything during the test. Also no rectangles are
    being invalidated yet, by my program. Just window resizing, and opening and then
    removing another window on top of mine.

    The first coordinates printed out look about right, when the window first opens. Then
    it keeps printing those same values.

    The BitBlt appears to be working fine, So updateclient(...) must be being called.

    Code:
    void updateclient(HWND hWnd)
    {	char str[20];
    	HDC hDcPaint;
    	PAINTSTRUCT ps;
    
    	hDcPaint = BeginPaint(hWnd, &ps);
    
    	BitBlt(hDcPaint, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom, 
    		hMemdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
    
    	Rectangle(hDcPaint, 50, 50, 200, 200);
    
    	_itoa(ps.rcPaint.top, str, 10);
    	TextOut(hDcPaint, 110, 60, str, strlen(str));
    
    	_itoa(ps.rcPaint.left, str, 10);
    	TextOut(hDcPaint, 60, 120, str, strlen(str));
    
    	_itoa(ps.rcPaint.right, str, 10);
    	TextOut(hDcPaint, 150, 120, str, strlen(str));
    
    	_itoa(ps.rcPaint.bottom, str, 10);
    	TextOut(hDcPaint, 110, 170, str, strlen(str)); 
    
    
    	EndPaint(hWnd, &ps);
    }
    Last edited by megafiddle; 10-05-2011 at 04:15 PM.

  9. #9
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Your BitBlt() is wrong.

    the width / height are only equal to the right/bottom if the left /top are zero.

    It should be width = (rect.right - rect.left) and height = (rect.bottom - rect.top)
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Ok, thanks. That was a dumb mistake. I knew better too.

    I took out the bitblt and still no difference. In fact it's just plain wierd.

    I put in a counter and added it to the printout so I would have something definite in there.
    I increment it each time a WM_PAINT comes in.

    It's not just the coordinate printout that's not changing; the counter printout is not changing
    either! Yet the counter is incrementing.

    I found that if I only cover and uncover part of the window, the coordinates and counter
    do not update in the printout. But if I cover and uncover the entire window, I get what looks
    like correct coordinates and a correct counter value.

    Each time I cover and uncover entire window, the dispayed count increments. Each time
    I cover and uncover only part of my window, displayed count doesn't change. But when I
    then cover and uncover entire window, the count display reflects all the cover/uncover that
    occurred.

    The counter increments every time, but does not print the new value every time!
    I'm thinking the program is crashing?

    Code:
    void updateclient(HWND hWnd)
    {	static int i = 0;	
    	char str[20];
    	HDC hDcPaint;
    	PAINTSTRUCT ps;
    
    	hDcPaint = BeginPaint(hWnd, &ps);
    
    //	BitBlt(hDcPaint, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom, 
    //		hMemdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
    
    	Rectangle(hDcPaint, 50, 50, 220, 220);
    
    	_itoa(ps.rcPaint.top+i, str, 10);
    	TextOut(hDcPaint, 110, 60, str, strlen(str));
    
    	_itoa(ps.rcPaint.left, str, 10);
    	TextOut(hDcPaint, 60, 120, str, strlen(str));
    
    	_itoa(ps.rcPaint.right, str, 10);
    	TextOut(hDcPaint, 150, 120, str, strlen(str));
    
    	_itoa(ps.rcPaint.bottom, str, 10);
    	TextOut(hDcPaint, 110, 170, str, strlen(str)); 
    
    	_itoa(i, str, 10);
    	TextOut(hDcPaint, 110, 190, str, strlen(str)); 
    	EndPaint(hWnd, &ps);
    
    	i++;
    }

  11. #11
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    A quick test confirms that BeginPaint() clips.

    That is you can not draw on any part of the client area outside the invalidated rect (rcPaint in the PAINTSTRUCT).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  12. #12
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Of course. The clipping rectangle is set equal to the rectangle in
    the paint structure. That's why my coordinate printout only works
    when the whole area becomes invalidated. At other times it's outside
    the clipping region.

  13. #13
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Quote Originally Posted by BeginPaint
    The BeginPaint function automatically sets the clipping region of the device context to exclude any area outside the update region.
    Those Microsofties are a sneaky lot aren't they

  14. #14
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Ok, I changed the coordinates in InvalidateRect() to include the area for the coordinate
    value display. Now I can see them update.

    BeginPaint does appear to limit the rectangle in the PaintStruct to the client area. If I try
    to extend the rectangle in InvalidateRect() outside the client area, the rectangle in the
    PaintStruct only includes that portion that was inside the client area.

    So the rectangle in the PaintStruct is the intersection of the client area and the rectangle
    specified in InvalidateRect().

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ MFC Rectangle Class?
    By ataman in forum C++ Programming
    Replies: 2
    Last Post: 04-30-2008, 07:51 AM
  2. Rectangle tangle help???
    By bluenoser in forum C++ Programming
    Replies: 5
    Last Post: 03-13-2003, 06:10 PM
  3. Rectangle
    By Vicious in forum Windows Programming
    Replies: 3
    Last Post: 06-03-2002, 10:15 PM
  4. rectangle
    By Unregistered in forum Game Programming
    Replies: 7
    Last Post: 04-06-2002, 06:10 PM
  5. Help With Rectangle,
    By incognito in forum Windows Programming
    Replies: 3
    Last Post: 03-30-2002, 12:43 PM