How do I change the background colour of an edit field on a dialog?

The following code will change the colour of a single edit field, with the ID value IDC_EDIT1 to a dark gray. We do this by returning an appropriately coloured brush from the WM_CTLCOLOR handler, and at the same time setting the background colour of any contained text to also be dark gray.

So, let's start by defining our colour. This is done as a constant COLORREF value (note the double R in that type name):

const COLORREF crefDarkGray = (RGB(128,128,128));

In the class header, we define some variables for creating and holding our brush:

LOGBRUSH m_DGBrushStruct;
HBRUSH m_DGBrush;

In the InitDialog handler, we create the brush:

m_DGBrushStruct.lbStyle = BS_SOLID;
m_DGBrushStruct.lbColor = crefDarkGray;
m_DGBrushStruct.lbHatch = 0;
m_DGBrush = ::CreateBrushIndirect (&m_DGBrushStruct);

Finally, we create a handler for the WM_CTLCOLOR message, and put some code in it to set our colours up as required:

HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
   HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
      
   switch (nCtlColor)
   {
      case CTLCOLOR_EDIT:
         if (pWnd->GetDlgCtrlID () == IDC_EDIT1)
         {
            pDC->SetBkColor (crefDarkGray);
            return m_DGBrush;
         }
         break;
      
      default:
         break;
   }
   return hbr;
}

There's a couple of interesting things about that code. Note the use of GetDlgCtrlID ? We can't compare the pWnd returned against a pWnd for the edit control, because OnCtlColor returns a temporary pointer, and comparisons against MFC temporary pointers won't work. Secondly, as I stated above, it only changes the background colour for the one specific edit control. If you want to change all edit controls, simply remove the IF statement.

Note that you delete brush handles using the DeleteObject API, not CloseHandle.

As an intellectual exercise, what if we want a disabled edit control to paint in the normal colour for an enabled window? This breaks normal UI usage of course, so I'm not suggesting you do it, but it presents an interesting problem. Here the technique is similar, but we have to know a small wrinkle : disabled edit boxes are treated like statics. Look at the following code, which is extracted from another OnCtlColor handler:

HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
   HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
      
   switch (nCtlColor)
   {
      case CTLCOLOR_STATIC:
         if (pWnd->GetDlgCtrlID () == IDC_EDIT1)
         {
            hbr = GetSysColorBrush (COLOR_WINDOW);
            pDC->SetBkColor (GetSysColor(COLOR_WINDOW));
            return (hbr);
         }
         break;

That code will paint the edit box and the background of any contained text in the normal colour for a window background, but the text remains gray so as to give feedback to the user that the edit field is indeed disabled. Plus it will react correctly if the windows colours are changed at runtime.

Download