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
icons have transparent pixels, no ?
GIF and PNG images can also have transparent pixels - maybe you're not testing with such an image
(http://www.infocellar.com/networks/graphics/images/globe1-transparent.gif)
(http://blogs.discovermagazine.com/intersection/files/2009/05/earth-transparent.png)
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?
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
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)
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
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
Jochen - give this a try...
INVOKE InvalidateRgn,hWnd,NULL,TRUE
INVOKE UpdateWindow,hWnd
you may not need UpdateWindow :P
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
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
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 :(
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.
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.
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
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...
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..).
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)
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
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
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...
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
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
I beg your pardon? ::)
: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
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.
GetMessage returns -1 if there is an error, but I can't see needing the check this once you app is debugged.
WM_CTLCOLORSTATIC:
SetBkColor
mov eax,hBrush
ret
:P
Dave,
In case that was an invitation to handle this message: It never arrives without the SetWindowText.
:wink
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