Приложения-диалоги
Базовым классом любого Windows-приложения, основанного на оконном интерфейсе, является класс cWinApp.
При создании приложения-диалога мастер построения MFC-приложения добавляет в проект два класса:
- класс приложения, производный от cWinApp;
- класс диалога, производный от CDialog.
Класс приложения имеет следующее объявление и реализацию:
// Заголовочный файл class CD1App : public CWinApp {public: CD1App(); public: virtual BOOL InitInstance(); // Первый // выполняемый метод // Implementation DECLARE_MESSAGE_MAP() }; extern CD1App theApp; // Переменная - приложение // Файл реализации D1.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" // CD1App BEGIN_MESSAGE_MAP(CD1App, CWinApp) // Обрабатываемые события ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() CD1App::CD1App(){ } // Конструктор CD1App theApp; BOOL CD1App::InitInstance() { CWinApp::InitInstance(); AfxEnableControlContainer(); SetRegistryKey(_T("Local AppWizard-Generated Applications")); CD1Dlg dlg; // Создание объекта диалога m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); // Отображение // диалога if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; // Завершение приложения }
Класс диалога имеет следующее объявление и реализацию:
// Заголовочный файл class CD1Dlg : public CDialog {public: CD1Dlg(CWnd* pParent = NULL); // Конструктор enum { IDD = IDD_D1_DIALOG }; // Ресурс диалога protected: // Поддержка DDX/DDV: virtual void DoDataExchange(CDataExchange* pDX); // Реализация protected: HICON m_hIcon;
// Функции таблицы обрабатываемых событий virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() }; // Файл реализации D1Dlg.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" class CAboutDlg : public CDialog // Класс // вспомогательного диалога {public: CAboutDlg(); enum { IDD = IDD_ABOUTBOX }; // Ресурс диалога protected: virtual void DoDataExchange(CDataExchange* pDX); protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX);} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // Класс окна диалога приложения CD1Dlg::CD1Dlg(CWnd* pParent /*=NULL*/) : CDialog(CD1Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CD1Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CD1Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // Методы обработки событий BOOL CD1Dlg::OnInitDialog() { CDialog::OnInitDialog(); ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); // Указатель // на системное меню if (pSysMenu != NULL) // Добавление пунктов к { CString strAboutMenu; //системному меню strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); // Определение крупной // пиктограммы SetIcon(m_hIcon, FALSE); // Определение мелкой пиктограммы return TRUE; } void CD1Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } void CD1Dlg::OnPaint() { CDialog::OnPaint(); }
HCURSOR CD1Dlg::OnQueryDragIcon() // Запрос курсора { return static_cast<HCURSOR>(m_hIcon); }
Листинг 19.1.
Для отображения окна диалога следует:
- создать ресурс диалога, имеющий конкретный вид диалогового окна, и разместить в нем требуемые элементы управления (каждый элемент управления также определяется своим идентификатором ресурса);
- создать класс, наследуемый от класса CDialog (или производного от него), и связать создаваемый класс с ресурсом диалога.
Связывание командных кнопок с методами - обработчиками событий и идентификаторов ресурсов элементов управления с переменными выполняется в редакторе ресурсов.
Для назначения кнопке метода обработчика события можно выполнить на ней двойной щелчок мышью (для события BN_CLICKED) или выделить элемент управления и выполнить команду контекстного меню Add Event Handler.
По умолчанию для командной кнопки, выполняющей завершение диалога, будет вставлен следующий метод - обработчик события:
void CD1Dlg::OnBnClickedOk() { OnOK(); // OnOK - метод базового класса CDialog }
Имя метода - обработчика события формируется из префикса On, имени события и идентификатора элемента управления.
Обработчик события добавляется как новый член класса диалога.
При добавлении каждого нового метода обработчика события в таблицу сообщений также добавляется новый вход.
Таблица сообщений (иногда называемая также таблицей событий) указывается между макросами BEGIN_MESSAGE_MAP иEND_MESSAGE_MAP. Макрос BEGIN_MESSAGE_MAP имеет два параметра - имя класса, обрабатывающего данные сообщения, и имя базового класса. Чтобы определить, что данный класс имеет таблицу сообщений, в заголовочном файле указывается макрос DECLARE_MESSAGE_MAP.
Например:
BEGIN_MESSAGE_MAP(CD1Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CD1Dlg::OnBnClickedOk) END_MESSAGE_MAP()
Каждый вход таблицы сообщений содержит имя события (например, ON_BN_CLICKED), идентификатор ресурса элемента управления (например, IDOK) и имя метода - обработчика события (например, &CD1Dlg::OnBnClickedOk).
Диалог может быть создан как:
- модальный диалог, завершение которого необходимо выполнить до продолжения работы с приложением (диалог отображается вызовом метода DoModal);
- немодальный диалог, позволяющий получать одновременный доступ к другим немодальным диалогам данного приложения (диалог создается вызовом метода Create и сразу отображается, если установлен стиль диалога WS_VISIBLE).
Для того чтобы отобразить созданный диалог как модальный, следует создать объект диалога и выполнить для него метод DoModal().
Например:
CD1Dlg dlg; INT_PTR nResponse = dlg.DoModal();
Если предполагается определить диалог как главное окно приложения, то необходимо для объекта приложения установить значение свойства m_pMainWnd (CWnd* m_pMainWnd;).
Например:
CD1Dlg dlg; m_pMainWnd = &dlg; // AfxGetApp()->m_pMainWnd // AfxGetApp() возвращает для // приложения указатель на // объект типа CWinApp INT_PTR nResponse = dlg.DoModal();
Для модального диалога следует проверять код завершения диалога.
Например:
INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { }
Для того чтобы отобразить диалог как немодальный, следует создать объект диалога и выполнить для него метод Create().
Например:
CMyDialog* pDialog; // Указатель на объект диалога void CMyWnd::OnSomeAction() { // pDialog может быть инициализирован как NULL // в конструкторе или классе CMyWnd pDialog = new CMyDialog(); if(pDialog != NULL) { BOOL ret = pDialog->Create(IDD_MYDIALOG,this); // Параметр // указывает используемый ресурс диалога if(!ret) AfxMessageBox("Ошибка при создании диалога"); pDialog->ShowWindow(SW_SHOW); } else AfxMessageBox("Ошибка с объектом диалога"); }