netmaestro wrote:The background for a button is drawn by the Operating System on Windows. Returning brushes for WM_CTLCOLORSTATIC and other such approaches will not have any effect. However, you can make your button look any way you choose by setting the #BS_OWNERDRAW style bit and responding to messages appropriately in code. There should be several examples of ownerdrawn buttons on the forums if you do a search.
Well in fact I was rather messing with skinning (and subclassing) the Windows Edit Control (the String Gadget) and was confronted with several problems.
It seems the listview is an exception, doing some validation in your place so you don't have to do it.
The first problem I had was flicking.. and after several days of investigation, I've found the (almost) bullet proof solution (valid for other gadgets too, especially if you use canvas). I say "almost" because there is one thing you can't do nothing about it: If the windows message queue is overloaded, then the paint messages (WM_PAINT,WM_ERASEBKGND,WM_NCPAINT) arrive too late to avoid flicking.
And what I've discovered is that one way to have the windows messages queue overloaded is to "forgot" to validate the region/rectangle you paint once you've done it, because else Windows keep on sending the paint message until the region is validated..
So the flicking problems, from what I get, have nothing to do with the fact you paint in the WM_ERASEBKGND or WM_PAINT event. Paint in WM_ERASEBKGND will not automagically make the problem disappear.
In short, if you don't need to erase the background (because your painting will take the entier client area), just return 1, and do your painting in WM_PAINT. The key then, is to
not forgot to validate the rectangle area you just paint by using:
( #Null for the entier client area but you can specify a smaller rectangle if you want).
Normaly, with this you are safe, even if your main windows is erasing its background with a plain color (and without using the SmartWindowRefresh( #MainWindow, 1 ) )
But for this to work, you have to paint exclusively into the client area, and not into the windows area (the 'NC' area).
This means you have to use:
Code: Select all
Protected rc.RECT, hDC.i
GetClientRect_( hWnd, @rc )
hDC = GetDC_( hWnd )
Instead of:
Code: Select all
GetWindowRect_( hWnd, @rc )
hDC = GetWindowDC_( hWnd )
I was first using the Non-Client area because I wanted to 'skin' the Edit Control with a custom image for the control borders. But unfortunately I did not found a solution to avoid flicking by using the Non-Client area.
So the solution was to set the client area with borders of 0 pixels (see below how) and do all the painting bliting etc.. into the client area.
But aside from the flicking problem, I was stuck with other problem, I was unable to avoid the Edit Control to paint without my permission

I was for most of the parts, except for the Caret for wich it seems there is nothing to do to hide it, and for the double click situation where the Edit Control decides to draw on screen even if you send SendMessage_ ( GadgetID(#StringEdit), #WM_SETREDRAW, 0, 0 ) right before sending it the double click message!
So the last solution I have in mind and wich I'm exploring now is to use a ghost control. My main gadget will be a CanvasGadget then I'll also create a always hidden (WM_SETREDRAW/0) StringGadget. I'll then send the input events from the canvas to the string control and use the EM_ messages to interact with it then paint the canvas with the result.
Regarding how to set the Client Area borders, here is my solution:
Code: Select all
Case #WM_WINDOWPOSCHANGING
; ...[ Local Variable ].................................................
Protected *wpos.WINDOWPOS = lParam
; ...[ Force #WM_NCCALCSIZE Message To Be Sent ]........................
*wpos\flags | #SWP_FRAMECHANGED
; ...[ Processed ]......................................................
ProcedureReturn 0
Case #WM_NCCALCSIZE
; ...[ MUST Calculate Client Area ].....................................
If wParam
; ...[ Local Variable ]...............................................
Protected *ncs.NCCALCSIZE_PARAMS = lParam
; ...[ Set New Client Size With Borders ].............................
*ncs\rgrc[0]\left = *ncs\lppos\x + cli_border_left
*ncs\rgrc[0]\right = *ncs\lppos\x + ( *ncs\lppos\cx - cli_border_right )
*ncs\rgrc[0]\top = *ncs\lppos\y + cli_border_top
*ncs\rgrc[0]\bottom = *ncs\lppos\y + ( *ncs\lppos\cy - cli_border_bottom )
; ...[ Processed ]......................................................
ProcedureReturn 0
EndIf
I'll report here the result with my 'ghost' control experiments, once I've got something.
Cheers,
Guy.