Немодальный
диалог
В предыдущем
разделе мы научились редактировать данные документа, воздействуя мышью непосредственно
на их представление, то есть облик документа, на экране монитора. Это довольно
грубый, но быстрый и эффективный способ, позволяющий получить заготовку некоторой
геометрии конструкции, которую впоследствии можно довести до желаемого состояния
с помощью таблиц (элементов управления типа grid) или обычных окон редактирования.
В практике проектирования геометрии устройств или описания геометрии расчетной
области часто используют некоторые стандартные заготовки, которые служат отправной
точкой для дальнейшей детализации и усложнения геометрии. Такие заготовки целесообразно
выбирать с помощью окон диалога, работающих в немодальном режиме и зачастую
называемых Toolbox-window. В них пользователь может выбрать одну из стандартных
заготовок геометрии устройства или изменить атрибуты текущей. Создайте с помощью
редактора диалогов Studio.Net форму диалога, которая выглядит так, как показано
на рис. 5.5. Типы элементов управления, размещенных в окне диалога, и их идентификаторы
сведены в табл. 5.1.
Рис. 5.5.
Вид окна диалога
Таблица.
5.1 Идентификаторы элементов управления
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Окно редактирования
Green
|
|
|
|
|
|
|
|
|
|
Окно редактирования
Color
|
|
Для трех кнопок
(TRI, PENT и STAR) установите стиль Owner draw, так как это будут не стандартные
кнопки, а кнопки с изображениями, управляемые классом CBitmapButton. Для ползунков
установите следующие стили: Orientation: Horizontal, TickMarks: True, AutoTicks:
True, Point: Top/Left.
Для управления
диалогом необходимо создать новый класс. Для этого можно воспользоваться контекстным
меню, вызванным над формой диалога.
- Выберите в контекстном
меню команду Add Class.
- В левом окне диалога
Add Class раскройте дерево Visual C++, сделайте выбор MFC * MFC Class
и нажмите кнопку Open.
- В окне мастера MFC Class
Wizard задайте имя класса CPolyDlg, в качестве базового класса выберите CDialog.
При этом станет доступным поле Dialog ID.
- В это поле введите или
выберите из выпадающего списка идентификатор шаблона диалога IDD_POLYCOLOR
и нажмите кнопку Finish.
Просмотрите
объявление класса CPolyDlg, которое должно появиться в новом окне PolyDlg.h.
Как видите, мастер сделал заготовку функции DoDataExchange для обмена данными
с элементами управления на форме диалога. Самих функций обмена типа DDX_ еще
нет, но мы их создадим немного позже.
Нестандартные
элементы управления
Рассмотрим,
как создаются элементы управления, имеющие индивидуальный нестандартный облик.
Сравнительно новым подходом в технологии создания таких элементов является обработка
подходящего сообщения не в классе родительского окна, а в классе, связанном
с элементом управления диалога. Такая возможность появилась в MFC начиная с
версии 4.0, и она носит название Message Reflection. Элементы управления Windows
посылают уведомляющие сообщения своим родительским (parent) окнам. Например,
многие элементы, в том числе и Edit controls, посылают сообщение WM_CTLCOLOR,
позволяющее родительскому окну выбрать кисть для закраски фона элемента. В версиях
MFC (до 4.0), если какой-либо элемент должен выглядеть не так, как все, то эту
его особенность обеспечивал класс родительского окна, обычно диалог. Теперь
к старому механизму обработки уведомляющих сообщений от дочерних (child) элементов
добавился новый, который позволяет произвести обработку уведомляющего сообщения
в классе самого элемента. Уведомляющее сообщение как бы отражается (reflected)
назад в класс дочернего окна элемента управления. Мы собираемся использовать
нестандартные окна редактирования (Red, Green, Blue и Color), с тем чтобы они
следили за изменением цвета, отражая текущий выбор как в числовом виде, так
и в виде изменяющегося цвета фона своих окон. Эту задачу можно выполнить, создав
класс (назовем его cclrEdit), производный от CEdit, и введя в него обработку
отражаемого сообщения =WM CTLCOLOR.
Примечание
Обратите внимание на символ
= перед идентификатором сообщения Windows. Он необходим, чтобы различить два
сообщения с одним именем. Наличие символа = означает принадлежность сообщения
к группе отражаемых (reflected) сообщений.
Применяя уже
известный вам подход, создайте класс cclrEdit с базовым классом CEdit. В процессе
определения атрибутов нового класса укажите существующие файлы (PolyDlg.h и
PolyDlg.cpp) в качестве места для размещения кодов нового класса. Если возникнут
окна диалогов с просьбой подтвердить необходимость погружения кодов в уже существующие
файлы, то ответьте утвердительно. Введите изменения в файл PolyDlg.h, так чтобы
он приобрел следующий вид:
#pragma
once
//=====
Класс нестандартного окна редактирования
class
CClrEdit :
public CEdit
{
DECLARE_DYNAMIC
(CClrEdit)
public:
CClrEdit
() ;
virtual
-CClrEdit () ;
void
ChangeColor (COLORREF clr) ; // Изменяем цвета
protected:
DECLARE_MESSAGE_MAP
()
private
:
COLORREF
ra_clrText; // Цвет текста
COLORREF
ra_clrBk; // Цвет фона
CBrush
m_brBk; // Кисть для закраски фона
};
//======
Класс для управления немодальным диалогом
class
CPolyDlg :
public CDialog
{
friend
class CClrEdit;
DECLARE_DYNAMIC
(CPolyDlg)
public
: enum ( IDD = IDD_POLYCOLOR } ;
//======
Удобный для нас конструктор
CPolyDlg
(CTreeDoc* p) ;
virtual
-CPolyDlg ( ) ;
//======
Отслеживание цвета
void
UpdateColor () ;
protected:
virtual void DoDataExchange (CDataExchange* pDX) ;
DECLARE_MESSAGE_MAP
( )
private :
CTreeDoc*
m_pDoc; // Обратный указатель
CBitmapButton
m_cTri; // Кнопки с изображениями
CBitmapButton
m_cPent;
CBitmapButton
m_cStar;
bool
ra_bScroll; // Флаг использования ползунка };
};
Мы изменили
конструктор класса CPolyDlg так, чтобы он имел один параметр — адрес документа,
который мы используем в качестве обратного указателя. Это поможет нам управлять
приложением, оставаясь в рамках методов диалогового класса. Теперь воспользуемся
услугами Studio.Net для создания функции-обработчика сообщения =WM_CTLCOLOR
в классе нестандартного окна редактирования.
- Поставьте фокус на элемент
CClrEdit дерева классов в окне Class View, перейдите в окно Properties и нажмите
кнопку Messages.
- Нажмите кнопку Categorized
и, нажав на маркер (-) Common, закройте список обычных сообщений.
- В оставшейся части списка
Reflected найдите сообщение =WM_CTLCOLOR и создайте функцию для его обработки,
выбрав <Add> в ячейке справа.
Найдите заготовку
тела функции ctlColor в файле PolyDlg.cpp и вставьте в нее следующие коды:
HBRUSH
CClrEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetTextColor
(m_clrText); // Цвет текста
pDC->SetBkColor
(m_clrBk); // Цвет подложки текста
return
m_brBk; // Возвращаем кисть
}
Создайте тело
вспомогательной функции ChangeColor, которую мы будем вызывать в те моменты
существования диалога, когда пользователь изменяет значения элементов управления
цветом:
void
CClrEdit::ChangeColor(COLORREF clr)
{
//======
Цвет текста - инвертирований цвет фона
m_clrText
= ~clr & Oxffffff;
m_clrBk
= clr;
//======
Создаем кисть цвета фона
m_brBk.DeleteObject();
m_brBk.CreateSolidBrush
(clr);
Invalidate
();
}
Главным управляемым
параметром является кисть (m_brBk), которую в ответ на отраженное сообщение
=WM_CTLCOLOR надо возвратить каркасу приложения. Попутно мы изменяем цвет текста
(setTextColor) и его подложки (setBkColor). Чтобы понять, что такое подложка
текста, при отладке временно закомментируйте строку
pDC->SetBkColor
(m_clrBk);
При изменении
(инвертировании) цвета текста мы вынуждены обнулять четвертый байт переменной
m_clrText. В более старых версиях Windows это действие было лишним. Теперь четвертый
байт используется для задания степени прозрачности при воспризведении растровых
изображений. Если он не равен нулю, то инвертирование цвета не проходит. Первые
три байта, как вы помните, задают три компонента (red, green, blue).
Изменение цвета
пользователем с помощью элементов управления будет мгновенно отслеживаться в
четырех полях диалога (три компонента цвета и суммарный цвет в окне Color).
Так как мы хотим отследить изменение цвета и в окне представления, управляемого
классом CDrawView, то мы добываем адрес родительского oкna.(GetParent) и вызываем
вспомогательную функцию UpdateDrawView.