Московский государственный университет имени М.В.Ломоносова
Опубликован: 01.11.2004 | Доступ: свободный | Студентов: 11271 / 455 | Оценка: 4.12 / 4.01 | Длительность: 19:20:00
ISBN: 978-5-9556-0077-9
Специальности: Программист
Лекция 19:

Библиотека классов MFC среды проектирования Visual Studio .NET. Диалоги

< Лекция 18 || Лекция 19: 1234 || Лекция 20 >

Приложения-диалоги

Базовым классом любого 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("Ошибка с объектом диалога");
}
< Лекция 18 || Лекция 19: 1234 || Лекция 20 >
Александр Демьяненко
Александр Демьяненко

Можно ли сдавать один и тот же тест несколько раз?
Или же один и тот же тест можно сдать лишь однажды?

Максим Стогний
Максим Стогний

Добрый день!

Скажите, пожалуйста, если в терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, в примере объявления указателя на метод использовали в формальном описании оба названия:

тип_метода (имя_класса::*имя_метода_указателя)
    (список параметров);
тип_функции (*имя_ функции_указателя)
    (список параметров);

при этом можно было  тип_функции во втором описании заменить на тип_метода? Т.е.:

тип_метода (*имя_ метода_указателя)
    (список параметров);