Обработка
сообщений от элементов управления
В окно диалога
мы ввели четыре кнопки, при нажатии которых в класс диалогового окна посылается
уведомляющее сообщение BN_CLICKED. При изменении данных в окнах редактирования
посылаются другие сообщения EN_CHANGE. При воздействии на ползунки также посылаются
уведомляющие сообщения, которые мы рассматривали в предыдущей главе. Однако,
как было отмечено, ползунки посылают и обычные сообщения (WM_HSCROLL или WM_VSCROLL).
Если в окне диалога имеется более одного ползунка, то сообщения от них удобно
обработать в одной функции, которая вызывается в ответ на сообщение о прокрутке.
Введите в класс CPolyDlg реакцию на WM_HSCROLL, так как наши ползунки ориентированы
горизонтально:
void
CPolyDlg::OnHScroll(UINT
nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
//======
Неинтересное для нас сообщение
if
(nSBCode==SB_ENDSCROLL)
return;
//======
Устанавливаем флаг сообщений от ползунков
m_bScroll
=
true;
//======
Узнаем идентификатор активного ползунка
switch(GetFocus()->GetDlgCtrlID())
{
case
IDC_RSLIDER:
//======
Считываем текущую позицию движка
m_nRed
= m_rSlider.GetPos();
//======
Синхронизируем поле, редактирования
SetDlgltemlnt(IDC_RED,
m_nRed);
break;
case
IDC_GSLIDER:
m_nGreen
= m_gSlider.GetPos();
SetDlgltemlnt(IDC_GREEN,
m_nGreen);
break;
case IDC_BSLIDER:
m_nBlue
= m_bSlider.GetPos() ;
SetDlgltemlnt(IDC_BLUE,
m_nBlue);
break;
}
//======
Снимаем флаг сообщений от ползунков
m_bScroll
=
false;
}
Сообщения от
всех ползунков обрабатываются в одной функции. Идентификатор активного ползунка
определяется путем последовательного вызова двух функций GetFocus и GetDlgctrliD,
являющихся методами класса cwnd.
Флаг сообщений
от ползунков (m_bScroll) понадобился нам для того, чтобы при синхронизации элементов
управления не происходили повторные вызовы функций-обработчиков. Дело в том,
что при изменении позиции ползунка мы должны привести в соответствие окно редактирования,
а при ручном изменении числа в окне редактирования мы должны синхронизировать
позицию ползунка. Но сообщение EN_CHANGE посылается как при ручном изменении,
так и при программном изменении с помощью функции SetDlgltemlnt. Проследим цепь
таких событий: пользователь подвинул движок ползунка, мы вызываем SetDlgltemlnt,
она провоцирует посылку сообщения EN_CHANGE, а обработчик этого сообщения корректирует
положение ползунка, которое и без того верно.
Введите в класс
диалога реакции на уведомления EN_CHANGE от четырех элементов IDC_PEN, IDC_RED,
IDC_GREEN И IDC_BLUE. Вы помните, что это надо делать с помощью кнопки Events
в окне Properties. Вставьте коды в остовы функций обработки, как показано ниже:
void
CPolyDlg::OnChangePen
(void)
{
BOOL
bSuccess; //====== Попытка преобразовать в число
UINT
nSize = GetDlgltemlnt(IDC_PEN, SbSuccess, FALSE);
if
(bSuccess && nSize < 101)
{
m_nPen
= nSize;
m_pDoc->m_Poly-m_nPenWidth
= m_nPen;
m_pDoc->UpdateDrawView();
}
}
Отметьте, что
здесь мы намеренно не пользуемся функцией UpdateData, которая провоцирует обмен
данными сразу со всеми полями окна диалога, так как хотим показать более экономный
способ выборочного (целевого) обмена с помощью функции GetDlgltemlnt. Правда,
при таком подходе не работают функции проверки данных типа DDV_ и приходится
производить проверку самостоятельно:
void
CPolyDlg::OnChangeRed
(void)
{
//======
Если сообщение спровоцировано ползунком,
//======
то обходим коды его синхронизации
if
(!m_bScroll)
{
m_nRed
= GetDlgltemlnt(IDC_RED, 0, FALSE);
m_rSlider.SetPos(m_nRed);
//======
Изменяем цвет фона окна редактирования
m_cRed.ChangeColor(RGB(m_nRed,
0, 0));
//======
Корректируем интегральный цвет
UpdateColor();
}
void
CPolyDlg::OnChangeGreen
(void)
{
if
(!m_bScroll)
{
m_nGreen
= GetDlgltemlnt(IDC_GREEN, 0, FALSE), m gSlider.SetPos(m_nGreen);
m_cGreen.ChangeColor(RGB(0,
m_nGreen, 0)); UpdateColor ();
}
void
CPolyDlg::OnChangeBlue(void)
{
if
(!m_bScroll)
{
m_nBlue
= GetDlglteralnt(IDC_BLUE, 0, FALSE);
m_bSlider.SetPos(m_nBlue);
}
m_cBlue.ChangeColor(RGB(0,
0, m_nBlue));
UpdateColor
();
}
Введите тело
вспомогательной функции, которая вычисляет интегральный цвет и вносит изменения,
перекрашивая окно диалога IDC_COLOR, и с помощью документа текущий полигон в
окне CDrawView:
void
CPolyDlg::UpdateColor()
{
COLORREF
clr = RGB (m_riRed,m_nGreen,m_nBlue) ;
m_cColor.ChangeColor(clr)
;
m_pDoc->m_Poly.m_BrushColor
= clr;
m_pDoc->UpdateDrawView();
}
С помощью Studio.Net
введите в класс диалога реакции на уведомляющие сообщения (BN_CLICKED) о нажатии
кнопок выбора стандартных геометрий для полигонов (IDCJTRI, IDC_PENT и IDC_STAR).
В них мы с помощью техники обратного указателя вновь обращаемся к документу
и используем его данные и методы для замены координат точек текущего полигона:
void
CPolyDlg::OnClickedTri(void)
{
m_pDoc->m_Poly.MakeTria()
;
m_pDoc->UpdateDrawView()
;
}
void
CPolyDlg::OnClickedPent(void)
{
m_pDoc->m_Poly.MakePent()
;
m_pDoc->UpdateDrawView()
;
}
void
CPolyDlg::OnClickedStar(void)
{
m_pDoc->m_Poly.MakeStar()
;
m_pDoc->UpdateDrawView();
}
Измените тело
конструктора диалогового класса, с тем чтобы при открытии диалога он смог запомнить
обратный указатель (адрес документа) и все его элементы были правильно инициализированы:
CPolyDlg::CPolyDlg(CTreeDoc*
p)
:
CDialog (CPolyDlg::IDD, 0)
{
m_pDoc
= p;
m_nPen
= p->m_Poly.m_nPenWidth;
//======
Расщепляем цвет фона текущего полигона
COLORREF
brush = p->m_Poly.m_BrushColor;
m_nRed
= GetRValue(brush); // на три компонента
m_nGreen
= GetGValue(brush);
m_nBlue
= GetBValue(brush) ;
m_bScroll
=
false; // Ползунки в покое