Шаг 289 - Изучаем сообщения на примере WM_CTLCOLOR

Это очень показательное сообщение. Сообщение WM_CTLCOLOR посылается каждый раз когда само окно или одно из его средств управления должно перерисоваться. В ответ должна вернуться кисть для перерисовки.

Итак, давайте изучать. Создаем приложение на базе MFC AppWizard с именем TestDlg как диалоговое окно. Для класса CTestDlgDlg вызовем Add Windows Message Handler. Найдем там сообщение WM_CTLCOLOR и добавим его обработку к классу.

////////////////////////////////
// CTestDlgDlg dialog

class CTestDlgDlg : public CDialog
{
	......
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

HBRUSH CTestDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO: Change any attributes of the DC here

	// TODO: Return a different brush if the default is not desired
	return hbr;
}

Давайте заменим кисть, чтобы окрасить окно в разные цвета:

HBRUSH CTestDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    pDC->SetBkColor(RGB(127,127,127));
    return (HBRUSH)::GetStockObject(GRAY_BRUSH);
}

Если Вы сейчас запустите приложение, то окно будет серым. Это нормально, мы так и хотели. Поместите на диалоговую панель Edit Box, Static Box. Запустите приложение. Они тоже будут серыми. Эти элементы управления спрашивают кисть для покраски у родителя, то есть они посылают сообщение диалоговому окну с просьбой указать чем красить. Давайте попробуем это исправить.

HBRUSH CTestDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	if (CTLCOLOR_EDIT == nCtlColor)
	{
		pDC->SetTextColor(RGB(0,0,0)); 
		pDC->SetBkColor(RGB(255,255,255));
		return (HBRUSH)::GetStockObject(WHITE_BRUSH);
	}

	if (CTLCOLOR_STATIC == nCtlColor)
	{
		pDC->SetBkColor(RGB(255,0,255));
		return (HBRUSH)::GetStockObject(GRAY_BRUSH);
	}

	pDC->SetBkColor(RGB(127,127,127));
    	return (HBRUSH)::GetStockObject(GRAY_BRUSH);
	
}

Вот теперь совсем другое дело. Белое поле редактирования, красный статический элемент. Работает. А что если у нас много элементов управления ??? Как разобраться какой красить ??? Поместите второй элемент управления и код для него:

HBRUSH CTestDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	if (CTLCOLOR_EDIT == nCtlColor)
	{
		UINT id = pWnd->GetDlgCtrlID();
		if (id == IDC_EDIT2)
		{
			pDC->SetTextColor(RGB(0,0,0)); 
			return (HBRUSH)::GetStockObject(WHITE_BRUSH);
		}
		if ( id == IDC_EDIT1)
		{
			pDC->SetTextColor(RGB(0,0,0)); 
			return (HBRUSH)::GetStockObject(DKGRAY_BRUSH);
		}
	}

	if (CTLCOLOR_STATIC == nCtlColor)
	{
		pDC->SetBkColor(RGB(255,0,255));
		return (HBRUSH)::GetStockObject(GRAY_BRUSH);
	}

    pDC->SetBkColor(RGB(127,127,127));
    return (HBRUSH)::GetStockObject(GRAY_BRUSH);
}

Как видите разобраться можно. Есть следующие идентификаторы:

Все это хорошо, только сейчас мы реализовали все как при программировании на WIN32 API без всяких там классов. Но в реальности правильно, если за закраску будет отвечать сам класс. Так должно быть. Не должен диалог отвечать за закраску своих элементов. Иначе при большом количестве идентификаторов ваша функция OnCtlColor() превратится в сплошной switch. Об этом в следующем шаге. А пока посмотрите на результат. Он у Вас должен быть такой же.

289.gif (1783 b)


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Каев Артем.