4 Диалоговые панели (1061079), страница 2
Текст из файла (страница 2)
При создании модальной диалоговой панели перед тем, как панель появится на экране, вызывается виртуальный метод OnInitDialog класса CDialog. По умолчанию OnInitDialog вызывает метод UpdateData и выполняет инициализацию органов управления. Если метод OnInitDialog переопределяется в классе диалоговой панели, в первую очередь необходимо вызвать метод OnInitDialog класса CDialog.
Метод UpdateData также вызывается некоторыми другими методами класса CDialog. Так, метод UpdateData вызывается, когда пользователь закрывает модальную диалоговую панель, нажимает кнопку "Ok". Заметим, что кнопка "Ok" должна иметь идентификатор IDOK. Если пользователь нажмет на кнопку "Cancel", имеющую идентификатор IDCANCEL, то диалоговая панель также закрывается, но метод UpdateData не вызывается и обмен данными не происходит.
Методу DoDataExchange, который служит для реализации механизмов автоматического обмена данными, передается указатель pDX на объект класса CDataExchange. Этот объект создается, когда инициируется процесс обмена данными вызовом функции UpdateData. Элементы данных класса CDataExchange определяют процедуру обмена данными, в том числе определяют, в каком направлении будет происходить этот обмен. Следует обратить внимание на то, что указатель pDX передается функциям DDX_ и DDV_.
Если к диалоговой панели добавить новые органы управления и связать их средствами ClassWizard с элементами данных класса CDlg, то в блоке AFX_DATA_MAP будут размещены вызовы и других функций DDX и DDV, необходимые для выполнения обмена данными.
Таблица сообщений диалоговой панели
Класс диалоговой панели должен обрабатывать сообщения от своих органов управления, поэтому он должен иметь таблицу сообщений. В заголовке таблицы сообщений указывается имя класса CDlg и имя базового класса CDialog. Таблица сообщений класса CDlg содержит только одну строку, в которой обрабатывается сообщение с кодом извещения ON_BN_CLICKED от кнопки "Clear". Когда пользователь нажимает кнопку, вырабатывается данное сообщение и вызывается его обработчик - метод OnClickedClear, определенный в классе CDlg.
Строки таблицы сообщений расположены в блоке AFX_MSG_MAP, поэтому для управления ими используется ClassWizard.
Две другие кнопки панели - "Ok" и "Cancel" - не представлены в таблице сообщений, но в приложении определены методы OnOK и OnCancel, которые вызываются при нажатии на них. Оказывается, для диалоговых панелей определены две стандартные кнопки - "Ok" и "Cancel", которым присвоены специальные идентификаторы IDOK и IDCANCEL.
Базовый класс CDialog, так же как и класс CMyDialog, содержит таблицу сообщений. Среди прочих сообщений в этой таблице определены командные сообщения с идентификаторами IDOK и IDCANCEL. Для обработки этих командных сообщений определены виртуальные методы OnOK и OnCancel. Поэтому, когда диалоговая панель содержит кнопки с идентификаторами IDOK и IDCANCEL, как правило, нет необходимости создавать для них обработчики.
Так как в таблице сообщений класса CDlg отсутствует макрокоманды для обработки сообщений от кнопок "Ok" и "Cancel", они передаются для обработки базовому классу CDialog. Здесь они обрабатываются виртуальными методами OnOK и OnCancel.
Метод OnOK, определенный в классе CDialog, копирует данные из полей диалоговой панели в связанные с ними переменные. Для этого вызывается метод UpdateData с параметром TRUE. Затем выполняется вызов метода EndDialog, который закрывает диалоговую панель и возвращает значение IDOK. Метод DoModal, который используется для создания диалоговой панели и вызывается в классе родительского окна, прекращает работу и возвращает IDOK.
Метод OnCancel, определенный в классе CDialog, еще проще, чем OnOK. Он только закрывает диалоговую панель и возвращает значение IDCANCEL. Копирование данных не происходит, так как пользователь отменил изменения, нажав кнопку "Cancel".
Так как методы OnOK и OnCancel определены в классе CDialog как виртуальные, то можно переопределить их в классе CDlg. В этом случае управление получат переопределенные методы, а не методы класса CDialog. Методы класса можно вызвать, явно указав класс CDialog.
Отображение модальной диалоговой панели
Для отображения модальной диалоговой панели сначала создается объект класса CDlg, который будет представлять диалоговую панель. Когда объект создан, диалоговая панель еще не появляется на экране, для этого нужно воспользоваться методом DoModal, определенным в классе CDialog. При вызове метода DoModal выполнение метода, вызвавшего модальный диалог, приостанавливается, пока пользователь не закроет диалоговую панель.
Для отображения модальной диалоговой панели обычно используется следующий код, размещаемый в методе класса приложения, в котором вызывается диалог (например, в методе-обработчике какого-либо сообщения для окна приложения):
#include “dlg.h”
……
// Создание объекта класса диалога
CDlg Dlg; // при необходимости можно в конструктор класса диалога
// передать указатель на родительское окно, по умолчанию
// диалог является модальным ко всему приложению
int result;
// Mожно проинициировать переменные класса
Dlg.m_Str=”Введите текст”;
// Проверка возвращаемого методом DoModal значения
if((result=Dlg.DoModal())==IDOK)
{
// Код, который вызывается, если пользователь нажимает кнопку "OK"
………
// Можно воспользоваться данными, полученными в процессе диалога
AfxMessageBox(MyDialog.m_Str);
}
else
if(result==IDCANCEL)
{
// Код, который вызывается, если нажата кнопка "Cancel"
………
}
……
Диалоговая панель - главное окно приложения
Диалоговую панель можно использовать и как главное окно приложения. Для этого также сначала следует создать шаблон панели и сгенерировать при помощи ClassWizard класс, отвечающий за работу панели. Затем можно модифицировать шаблон и класс панели для нужд приложения и вызвать эту панель в переопределении метода InitInstance главного класса приложения, наследованного от CWinApp.
В этом случае файл реализации главного класса приложения будет иметь примерно следующий вид:
#include <afxwin.h>
#include файл определения главного класса приложения
#include файл определения класса диалога
BOOL CApp::InitInstance()
{
// Создание объекта класса диалога
CDlg Dlg;
// Указатель на объект класса диалога присваивается переменной
// m_pMainWnd класса CWinApp (процесс присоединения объекта
// главного окна к объекту-приложению)
m_pMainWnd= &Dlg;
// Отображение на экране диалоговой панели.
int result=Dlg.DoModal();
// Проверка возвращаемого методом DoModal значения
if(result==IDOK)
{
……
}
else
if(result==IDCANCEL)
{
……
}
// Так как диалоговая панель закрыта, то следует возвратить
// значение FALSE, чтобы завершить работу приложения
return FALSE;
}
Немодальная диалоговая панель
Процедура создания и использования немодальной диалоговой панели несколько отличается от процедуры создания модальной диалоговой панели.
Панель и ее класс диалога
Как и в случае с модальной диалоговой панелью, в первую очередь необходимо создать шаблон диалоговой панели и добавить его в файл ресурсов приложения. Затем нужно создать класс CDlg, управляющий диалоговой панелью, - класс диалоговой панели. Этот класс наследуется непосредственно от базового класса CDialog. Затем можно модифицировать шаблон и класс панели для нужд приложения.
В классе немодального диалога следует переопределить метод Create базового класса CDialog следующим образом:
void CDlg::Create(CWnd* pParent) { CDialog::Create(IDD,pParent);
// Вызов метода базового класса
Parent=pParent; // окно-родитель }
Предварительно в класс диалога необходимо добавить элемент Parent - указатель на родительский объект, например, CWnd *Parent - указатель на родительское окно. Если родительский объект не окно, то можно добавить в метод Create параметр, отвечающий за передачу указателя на родительский объект, и присвоить его переменной Parent, объявив его в определении класса как указатель на объект соответствующего типа. Указатель на родительский объект позволяет при необходимости вызывать для родительского объекта методы его класса непосредственно из методов класса диалога, что обеспечивает связь немодального диалога и его родительского объекта.
В переопределенном методе Create следует обязательно вызвать метод Create базового класса CDialog. Именно этот метод создает окно диалоговой панели. В классе CDialog определены два прототипа метода Create. Один позволяет указать диалоговую панель через ее текстовое имя, а другой - через числовой идентификатор. Метод Create возвращает управление сразу после отображения на экране диалоговой панели. Он возвращает ненулевое значение, если создание диалоговой панели завершилось успешно, и нуль в противном случае.
При помощи ClassWizard в классе CDlg также следует создать заготовки методов-обработчиков сообщений от кнопок IDOK (OnOK) и IDCANCEL (OnCancel) и для сообщения WM_DESTROY (OnDestoy). Затем необходимо изменить методы OnOK и OnCancel так, чтобы они вызывали только метод DestoyWindow. Если в методе Create предусматривается динамическое выделение блоков памяти, тогда в методе OnDestoy необходимо освободить занимаемую память.
Класс родительского объекта
Для обеспечения работы с немодальным диалогом сначала необходимо в классе приложения, в котором вызывается диалог (например, в классе окна приложения), объявить элемент Dlg класса CDlg. Родительский объект в методах своего класса может вызывать для диалоговой панели методы ее класса через объект Dlg, что обеспечивает связь родительского объекта и порождаемого им немодального диалога.
В момент создания объекта класса CDlg диалоговая панель как окно еще не создана и не появляется на экране. Для этого надо вызвать метод Create класса CDlg. Если диалоговая панель имеет стиль WS_VISIBLE, то она сразу появляется на экране. В противном случае для этого надо вызвать метод ShowWindow. Итак, в методе, который вызывает немодальный диалог (например, в методе-обработчике какого-либо сообщения для окна приложения), следует проверить, не отображается ли уже эта диалоговая панель, а затем создать ее методом Create класса CDlg:
if(Dlg.GetSafeHwnd()==NULL) Dlg.Create(this);
Чтобы закрыть немодальную диалоговую панель, можно воспользоваться методом DestroyWindow:
if(Dlg.GetSafeHwnd()!=NULL) Dlg.DestroyWindow();
Метод DestroyWindow определен в классе CWnd, следовательно, его можно вызывать для объектов класса диалоговой панели.