The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: jj2007 on October 28, 2011, 09:27:14 PM

Title: Force background erase of a static control
Post by: jj2007 on October 28, 2011, 09:27:14 PM
I am working on an image viewer (here (http://www.masm32.com/board/index.php?topic=12460.msg148511#msg148511)) and stumbled over something strange: When I display icons, they sometimes do not erase the background of the static control that I use as a canvas. It works fine for jpg, png, gif etc, but the icons are stubborn.

Question: How would you force a background erase on a static control? I tried various options in the WM_PAINT handler but no success :(

  CASE WM_PAINT
   invoke GetClientRect, hWnd, addr rc
   invoke MoveWindow, hStatic, 0, 0, rc.right, rc.bottom, 0
   invoke InvalidateRect, hStatic, 0, 0
Title: Re: Force background erase of a static control
Post by: dedndave on October 28, 2011, 09:38:36 PM
icons have transparent pixels, no ?

GIF and PNG images can also have transparent pixels - maybe you're not testing with such an image
Title: Re: Force background erase of a static control
Post by: dedndave on October 28, 2011, 09:41:36 PM
(http://www.infocellar.com/networks/graphics/images/globe1-transparent.gif)

(http://blogs.discovermagazine.com/intersection/files/2009/05/earth-transparent.png)
Title: Re: Force background erase of a static control
Post by: jj2007 on October 28, 2011, 09:42:19 PM
Quote from: dedndave on October 28, 2011, 09:38:36 PM
icons have transparent pixels, no ?

I guess so, yes, but that is not a good excuse for not erasing the background after an InvalidateRect... ::)

What's that cute globe about?
Title: Re: Force background erase of a static control
Post by: dedndave on October 28, 2011, 09:44:37 PM
oh - ok
how about the BkMode for the DC ?
what value are you using for the hrgbBackground of WNDCLASSEX when you register the window ?
or - if it's a system class - GetWindowLong

sounds like NULL_BRUSH is in there someplace

the globes are GIF/PNG transparencies   :P
Title: Re: Force background erase of a static control
Post by: jj2007 on October 28, 2011, 09:47:31 PM
Quote from: dedndave on October 28, 2011, 09:44:37 PM
how about the BkMode for the DC ?

Sounds promising, thanks. Will test it when I wake up tomorrow :8)
Title: Re: Force background erase of a static control
Post by: qWord on October 28, 2011, 11:05:40 PM
Quote from: jj2007 on October 28, 2011, 09:27:14 PM invoke InvalidateRect, hStatic, 0, 0
Have you tried this one:
Quoteinvoke InvalidateRect, hStatic, 0, 1
:bg

BTW: If you want to draw an image, whereas one color should be transparent, you can use image attributes:
Quote.if rv(GdipCreateImageAttributes,ADDR imgAttr) != GpStatusOk
    ; error
.endif
.if rv(GdipSetImageAttributesColorKeys,imgAttr,ColorAdjustTypeDefault,1,Color,Color) != GpStatusOk
    invoke GdipDisposeImageAttributes,imgAttr
    ; error
.endif
;...
invoke GdipDrawImageRectRectI,graphics,image,destX,destY,destWidth,destHeight,srcX,srcY,SrcWidth,SrcHeight,UnitPixel,imgAttr,0,0
;...
invoke GdipDisposeImageAttributes,imgAttr
Title: Re: Force background erase of a static control
Post by: jj2007 on October 29, 2011, 06:07:39 AM
Quote from: qWord on October 28, 2011, 11:05:40 PM
Quote from: jj2007 on October 28, 2011, 09:27:14 PM invoke InvalidateRect, hStatic, 0, 0
Have you tried this one:
Quoteinvoke InvalidateRect, hStatic, 0, 1
:bg
Yes, no effect :toothy

Quote
BTW: If you want to draw an image, whereas one color should be transparent, you can use image attributes:
Quote.if rv(GdipCreateImageAttributes,ADDR imgAttr) != GpStatusOk
    ; error
.endif
.if rv(GdipSetImageAttributesColorKeys,imgAttr,ColorAdjustTypeDefault,1,Color,Color) != GpStatusOk
    invoke GdipDisposeImageAttributes,imgAttr
    ; error
.endif
;...
invoke GdipDrawImageRectRectI,graphics,image,destX,destY,destWidth,destHeight,srcX,srcY,SrcWidth,SrcHeight,UnitPixel,imgAttr,0,0
;...
invoke GdipDisposeImageAttributes,imgAttr
Nice find, qWord. For the time being, I will leave this tricks to the macro haters, although adding two paras would not bloat the code excessively, either: The whole GdiPlus part stands currently at 253 bytes :wink
Title: Re: Force background erase of a static control
Post by: dedndave on October 29, 2011, 06:21:02 AM
Jochen - give this a try...

        INVOKE  InvalidateRgn,hWnd,NULL,TRUE
        INVOKE  UpdateWindow,hWnd


you may not need UpdateWindow   :P
Title: Re: Force background erase of a static control
Post by: fearless on October 29, 2011, 08:21:58 AM
Not sure if this would work:
.elseif eax == WM_CTLCOLORSTATIC
invoke GetWindowLong,lParam,GWL_ID       
.if eax == IDC_ICON ; static holder for icon
invoke SetBkMode,wParam,HOLLOW_BRUSH
invoke GetStockObject,HOLLOW_BRUSH
ret
.endif


or even just:
.elseif eax == WM_CTLCOLORSTATIC
invoke GetWindowLong,lParam,GWL_ID       
.if eax == IDC_ICON ; static holder for icon
ret
.endif
Title: Re: Force background erase of a static control
Post by: ToutEnMasm on October 29, 2011, 12:03:59 PM

here is a sample for a listbox,but there is one type of message by control.
http://www.masm32.com/board/index.php?topic=14758.msg146261#msg146261
Title: Re: Force background erase of a static control
Post by: jj2007 on October 29, 2011, 05:02:40 PM
Thanks, Dave, Fearless & ToutEnMasm. The problem is that the message never arrives...

Quote      invoke InvalidateRect, edi, 0, 1   ; prepare for painting, erase background
      sub esp, PAINTSTRUCT   ; create a local ps
      invoke BeginPaint, edi, esp
      invoke GdipCreateFromHDC, eax, esi  ; create graphics object
      sub esp, RECT   ; create a slot of paras for GdipDrawImageRectI
      invoke GetClientRect, edi, esp   ; use full control
      push [ebx]   ; imageObj
      push [esi]   ; graphicsObj; now stretch or draw image - see GdiPlus error codes (http://msdn.microsoft.com/en-us/library/ms534175.aspx)
      call GdipDrawImageRectI   ; invoke GdipDrawImageRectI, [esi], [ebx], [eax.RECT.left, top, right, bottom]
      invoke GdipDeleteGraphics, [esi]   ; release graphics object
      invoke EndPaint, edi, esp
      add esp, PAINTSTRUCT   ; release local ps
[/color]

The code works absolutely fine, no error messages, except that the background apparently does not get erased. However, if I disable the snippet above, the WM_CTLCOLORSTATIC message is there (and, well, the image is lost :bg).

Apparently, it is not the GdiPlus stuff but rather the BeginPaint/EndPaint sequence itself that blocks the background message :(
Title: Re: Force background erase of a static control
Post by: dedndave on October 29, 2011, 05:41:04 PM
i have never seen InvalidateRect used inside the WM_PAINT handler
that makes no sense
generally, the function is used to cause a WM_PAINT (and erase bg) sequence

QuoteThe invalidated areas accumulate in the update region until the region is processed when the next
WM_PAINT message occurs or until the region is validated by using the ValidateRect or ValidateRgn function.

The system sends a WM_PAINT message to a window whenever its update region is not
empty and there are no other messages in the application queue for that window.

If the bErase parameter is TRUE for any part of the update region, the
background is erased in the entire region, not just in the specified part.
Title: Re: Force background erase of a static control
Post by: jj2007 on October 29, 2011, 06:11:47 PM
Quote from: dedndave on October 29, 2011, 05:41:04 PM
i have never seen InvalidateRect used inside the WM_PAINT handler
that makes no sense
generally, the function is used to cause a WM_PAINT (and erase bg) sequence

Thanks, Dave. I had erroneously thought that the WM_PAINT handler of the main window can be used to force a paint message on the children. Wrong...
FillRect is one solution, but for non-transparent images it means flicker, so it is probably better to keep it outside the wrapper.
Title: Re: Force background erase of a static control
Post by: dedndave on October 29, 2011, 07:33:41 PM
you got me thinking - here is how i think it works   :P
WM_PAINT is first sent to the parent window
it is then sent "upwards" in the Z-order chain to the child windows, which i guess would include controls
maybe the problem you are experiencing is related to the value you return in EAX

and - what do you do for WM_ERASEBKGND ?
if it does not exit with the correct return value or does not go to DefWindowProc, you may have troubles
Title: Re: Force background erase of a static control
Post by: jj2007 on October 29, 2011, 08:16:38 PM
Quote from: dedndave on October 29, 2011, 07:33:41 PM
and - what do you do for WM_ERASEBKGND ?
if it does not exit with the correct return value or does not go to DefWindowProc, you may have troubles

Not handled...
Title: Re: Force background erase of a static control
Post by: ToutEnMasm on October 30, 2011, 07:55:27 AM

Perhaps that the icon format is not supported by the static control.
Find a function who translate it in a bitmap format (I know none) and all will work as other formats(jpg..).
Title: Re: Force background erase of a static control
Post by: jj2007 on October 30, 2011, 09:00:23 AM
Yves,
  CASE WM_PAINT
invoke GetClientRect, hWnd, addr rc
invoke MoveWindow, hStatic, 0, 0, rc.right, rc.bottom, 1
ImgPaint hStatic, 0, "\masm32\RichMasm\icons\Bell.ico"

... works just fine. The problem is transparency, see below. Workaround is FillRect but I was hoping for another solution...
(http://www.masm32.com/board/index.php?action=dlattach;topic=17636.0;id=9887)
Title: Re: Force background erase of a static control
Post by: dedndave on October 30, 2011, 12:13:20 PM
i like it   :bg

there is another way to go....
pick an icon that has no transparency or modify the icon by filling it in
one way to do that is to put the icon on the desired background, then copy it to a bitmap
Title: Re: Force background erase of a static control
Post by: dedndave on October 30, 2011, 12:57:26 PM
i am a little confused as to how you created the static control, however   :P
if you used the pre-defined system class, it should have a background color, defined by the class 'static'
for example, when an icon is placed in a MessageBox, it uses a static control
that class has a WNDCLASSEX.hbrBackground member that i believe is COLOR_BTNFACE+1
Title: Re: Force background erase of a static control
Post by: qWord on October 30, 2011, 01:11:25 PM
Static controls have the class style CS_PARENTDC. If you do not clip the statics region while drawing, you will paint over the controls content. The Window-style WS_CLIPCHILDREN should help in this case...
Title: Re: Force background erase of a static control
Post by: jj2007 on October 30, 2011, 05:17:00 PM
There is nothing strange in the creation of the static except that I saved a WM_CREATE handler. And the children are clipped, too...
LOCAL msg:MSG, wcex:WNDCLASSEX
call ClearLocVars ; zero WNDCLASSEX
ebxNull equ <ebx>
xor ebx, ebx ; ebxNull
lea esi, wcex
wc equ <[esi.WNDCLASSEX]>
m2m wc.cbSize, WNDCLASSEX
m2m wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, offset WndProc
m2m wc.hbrBackground, COLOR_BTNFACE+1
mov wc.lpszClassName, Chr$("MB GUI")
mov wc.hInstance, rv(GetModuleHandle, ebxNull)
mov wc.hIcon, rv(LoadIcon, eax, IDI_APPLICATION) ; eax=hInstance
mov wc.hIconSm, eax
mov wc.hCursor, rv(LoadCursor, ebxNull, IDC_ARROW)
invoke RegisterClassEx, esi
invoke CreateWindowEx, WS_EX_CLIENTEDGE,
wc.lpszClassName, ebxNull,
WS_CAPTION or WS_THICKFRAME or WS_CLIPCHILDREN or WS_VISIBLE,
-127, -127, ebxNull, ebxNull,\ ; for now, outside of visible screen
ebxNull, ebxNull, wc.hInstance, ebxNull
invoke CreateWindowEx, ebxNull, Chr$("static"), ebxNull,
WS_CHILD or WS_VISIBLE, ebxNull, ebxNull, ebxNull, ebxNull,
eax, 123, wc.hInstance, ebxNull ; eax=retval cwex main, 123=IdStatic
mov hStatic, eax
add esi, wc.cbSize ; lea esi, msg but one byte shorter ;-)
.Repeat
invoke GetMessage, esi, ebxNull, ebxNull, ebxNull
.Break .if !eax
; invoke TranslateMessage, esi
invoke DispatchMessage, esi
.Until 0
Title: Re: Force background erase of a static control
Post by: qWord on October 30, 2011, 06:11:55 PM
Quote from: jj2007 on October 30, 2011, 05:17:00 PM
invoke GetMessage, esi, ebxNull, ebxNull, ebxNull
.Break .if !eax

:naughty:
Quote.Break .if !eax || eax == -1
:toothy
Title: Re: Force background erase of a static control
Post by: jj2007 on October 30, 2011, 07:06:22 PM
I beg your pardon? ::)
Title: Re: Force background erase of a static control
Post by: dedndave on October 30, 2011, 08:18:59 PM
 :lol
i think he is pulling your leg

try this
        invoke CreateWindowEx, ebxNull, Chr$("static"), ebxNull,
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS, ebxNull, ebxNull, ebxNull, ebxNull,
                eax, 123, wc.hInstance, ebxNull ; eax=retval cwex main, 123=IdStatic


on an unrelated note, you can use CW_USEDEFAULT,SW_HIDE to hide the window until later   :P
        invoke CreateWindowEx,WS_EX_CLIENTEDGE,wc.lpszClassName, ebxNull,
                WS_CAPTION or WS_THICKFRAME or WS_CLIPCHILDREN,
                CW_USEDEFAULT,SW_HIDE, ebxNull, ebxNull,\ ; hidden for now
                ebxNull, ebxNull, wc.hInstance, ebxNull
Title: Re: Force background erase of a static control
Post by: jj2007 on October 30, 2011, 10:20:26 PM
Quote from: dedndave on October 30, 2011, 08:18:59 PM
try this
        invoke CreateWindowEx, ebxNull, Chr$("static"), ebxNull,
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS, ebxNull, ebxNull, ebxNull, ebxNull,
                eax, 123, wc.hInstance, ebxNull ; eax=retval cwex main, 123=IdStatic

No success. But I found a workaround (edi=hStatic):

      invoke InvalidateRect, edi, 0, 0   ; prepare for painting (erase background won't work)
      sub esp, PAINTSTRUCT   ; create a local ps
      invoke BeginPaint, edi, esp
      invoke GdipCreateFromHDC, eax, esi  ; create graphics object
      invoke SetWindowText, edi, 0   ; this one does erase the background, hooray!
      sub esp, RECT   ; create a slot of paras for GdipDrawImageRectI
      invoke GetClientRect, edi, esp   ; use full control
      push [ebx]   ; imageObj
      push [esi]   ; graphicsObj; now stretch or draw image - see GdiPlus error codes (http://msdn.microsoft.com/en-us/library/ms534175.aspx)
      call GdipDrawImageRectI   ; invoke GdipDrawImageRectI, [esi], [ebx], [eax.RECT.left, top, right, bottom]
      invoke GdipDeleteGraphics, [esi]   ; release graphics object
      invoke EndPaint, edi, esp
      add esp, PAINTSTRUCT   ; release local ps


:bg

An additional flag will be needed, because while this is needed for transparent icons, it is absolutely awful for big JPGs.
Title: Re: Force background erase of a static control
Post by: MichaelW on November 01, 2011, 12:38:08 AM
GetMessage returns -1 if there is an error, but I can't see needing the check this once you app is debugged.
Title: Re: Force background erase of a static control
Post by: dedndave on November 01, 2011, 02:02:25 AM
WM_CTLCOLORSTATIC:
SetBkColor
mov eax,hBrush
ret

:P
Title: Re: Force background erase of a static control
Post by: jj2007 on November 01, 2011, 06:20:28 AM
Dave,

In case that was an invitation to handle this message: It never arrives without the SetWindowText.

:wink
Title: Re: Force background erase of a static control
Post by: dedndave on November 01, 2011, 07:17:49 AM
well - i am still sceptical about the Invalidate call inside WM_PAINT   :P

but, that was the solution to NoCforMe's checkbox problem in the other thread - thought it may be helpful, here