В окно диалога мы ввели четыре кнопки, при нажатии которых в класс диалогового окна посылается уведомляющее сообщение 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; // Ползунки в покое