Setting the Color for the Dialog Background and for Controls

You can change the background color of individual dialogs or specific controls in a dialog, but you have to do some extra work. The parent dialog is sent a WM_CTLCOLOR message for each control immediately before the control is displayed. A WM_CTLCOLOR message is also sent on behalf of the dialog itself. If you map this message in your derived dialog class, you can set the foreground and background text colors and select a brush for the control or dialog nontext area.

Following is a sample OnCtlColor function that sets all edit control backgrounds to yellow and the dialog background to red. The m_hYellowBrush and m_hRedBrush variables are data members of type HBRUSH, initialized in the dialog's OnInitDialog function. The nCtlColor parameter indicates the type of control, and the pWnd parameter identifies the specific control. If you wanted to set the color for an individual edit control, you would convert pWnd to a child window ID and test it.

HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    if (nCtlColor == CTLCOLOR_EDIT) {
        pDC->SetBkColor(RGB(255, 255, 0));  // yellow
        return m_hYellowBrush;
    if (nCtlColor == CTLCOLOR_DLG) {
        pDC->SetBkColor(RGB(255, 0, 0));    // red
        return m_hRedBrush;
    return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

The dialog does not post the WM_CTLCOLOR message in the message queue; instead, it calls the Win32 SendMessage function to send the message immediately. Thus the message handler can return a parameter, in this case a handle to a brush. This is not an MFC CBrush object but rather a Win32 HBRUSH. You can create the brush by calling the Win32 functions CreateSolidBrush, CreateHatchBrush, and so forth.

For Win32 Programmers

Actually, Win32 no longer has a WM_CTLCOLOR message. It was replaced by control-specific messages such as WM_CTLCOLORBTN, WM_CTLCOLORDLG, and so on. MFC and ClassWizard process these messages invisibly, so your programs look as though they're mapping the old 16-bit WM_CTLCOLOR messages. This trick makes debugging more complex, but it makes portable code easier to write. Another option would be to use the ON_MESSAGE macro to map the real Win32 messages.

If your dialog class (or other MFC window class) doesn't map the WM_CTLCOLOR message, the framework reflects the message back to the control. When you study window subclassing in Chapter 16, you'll learn how to write your own control window classes that can process these reflected messages.