MORE INFORMATION
The CDK documentation states that to support the BackColor property, you
must send a WM_CTLCOLOR message to get a brush that contains the background
color. (See page 39 of the CDK documentation for more information.)
However, the CDK documentation does not specifically describe where you
need to put this code or how it should be structured. The Circ3 example
implements a functional BackColor property, but the code is not very
generic.
Example
The following sample code demonstrates how to add a generic BackColor
property to your custom control. Essentially, you add code to your Control
Procedure to monitor the following messages:
VBM_SETPROPERTY - so you can determine when the backcolor changes.
WM_ERASEBKGND - so you can repaint the background.
WM_PAINT - BeginPaint sends the WM_ERASEBKGND message.
Process VBM_SETPROPERTY so that you can determine when the BackColor
property is set. When the property is set, invalidate the window. You can
do this by calling InvalidateRect. Be sure to specify TRUE as the third
argument so that the background will be repainted.
When a section of the window is invalidated, a WM_PAINT message is posted
to the window. In your handling of the WM_PAINT message, you will usually
call BeginPaint. BeginPaint will send a WM_ERASEBKGND message to your
application if the InvalidateRect call specified that the background
needed to be erased.
Handle the painting of the background in your WM_ERASEBKGND handler. Send a
WM_CTLCOLOR message to the parent window. The parent window will return a
handle to a brush of the correct color. Then you can use that brush to
paint your window.
NOTE: Do not delete the brush.
Sample Code - Example Implementation of BackColor Property
Below is a code snippet taken from a control procedure that implements the
BackColor property:
// Check to see whether BackColor has been set.
case VBM_SETPROPERTY:
if( wp == IPROP_BACKCOLOR )
InvalidateRect(hwnd, NULL, TRUE); // Force a repaint.
break;
// Paint the background.
case WM_ERASEBKGND:
{
HBRUSH hbr, hbrOld=NULL;
RECT rect;
// Get window coordinates, and normalize.
GetWindowRect(hwnd, &rect);
rect.right = rect.right - rect.left; // Get width.
rect.bottom = rect.bottom - rect.top; // Get height.
rect.left = rect.top = 0;
// Get a brush with the background color.
hbr = (HBRUSH)SendMessage(GetParent(hwnd), WM_CTLCOLOR, (HDC)wp,
MAKELONG(hwnd, 0));
// If we got a brush, select it into our DC.
if( hbr )
hbrOld = SelectObject((HDC)wp, hbr);
// Paint the background.
FillRect((HDC)wp, &rect, hbr);
// If we selected an object, restore old object.
if( hbrOld )
SelectObject((HDC)wp, hbrOld);
// Return a non-zero, indicating we processed a message.
return 1;
}
// Paint the control (assumes we have a PaintRoutine).
case WM_PAINT:
if( wp ) PaintRoutine(hwnd, (HDC) wp); // Paint to given HDC.
else // Paint to window's HDC.
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
PaintRoutine(hwnd, ps.hdc);
EndPaint(hwnd, &ps);
}
break;
Sample Code - Example PaintRoutine
Here is some code for an example PaintRoutine:
void PaintRoutine(HWND hwnd, HDC hdc)
{
RECT rect;
char msg[] = "Painting the control";
// TextOut will work with any DC.
TextOut(hdc, 0, 0, msg, sizeof(msg) - 1);
}