Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

 ATLASSERT(m_bModal); // must be a modal dialog

 return ::EndDialog(m_hWnd, nRetCode);

}

Здесь следует обратить внимание всего на две вещи. Во-первых, в качестве диалоговой процедуры задаётся StartDialogProc. Благодаря этому к создаваемому диалогу подключается механизм обработки сообщений, рассмотренный в предыдущем разделе. Во-вторых, в качестве идентификатора ресурса диалога используется константа IDD. Вам необходимо определить её в производном классе, чтобы WTL знала, какой диалог требуется создать. В принципе, можно сделать IDD

и статической переменной производного класса, но прибегать к этому приёму на практике приходится не часто.

ПРИМЕЧАНИЕ

Библиотека MFC не использует функцию DialogBox(Param). Вместо этого она создаёт немодальный диалог, а затем эмулирует поведение модального. Благодаря этому программировать модальные диалоги в MFC гораздо удобнее, чем на "чистом" Win32 API (а значит, и в WTL). Проблема в том, что функция DialogBox(Param) создаёт свой собственный цикл сообщений, до которого не так-то просто добраться. Если нам потребуется, к примеру, внедрить в него трансляцию акселераторов, придётся прибегать к различным неочевидным приёмам.

Немодальный диалог создаётся с использованием функции Create и разрушается вызовом DestroyWindow. Реализация обоих методов также достаточно очевидна.

// modeless dialogs

HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) {

 ATLASSERT(m_hWnd == NULL);

 _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT<TBase>*)this);

#ifdef _DEBUG

 m_bModal = false;

#endif //_DEBUG

 HWND hWnd = ::CreateDialogParam(_Module.GetResourceInstance, MAKEINTRESOURCE(T::IDD),

hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);

 ATLASSERT(m_hWnd == hWnd);

 return hWnd;

}

BOOL DestroyWindow {

 ATLASSERT(::IsWindow(m_hWnd));

 ATLASSERT(!m_bModal); // must not be a modal dialog

 return ::DestroyWindow(m_hWnd);

}

С учётом всего сказанного, типичный класс диалога, порождённый от CDialogImpl<>, выглядит так (в качестве параметра шаблона задаётся имя класса, который вы порождаете).

class CMyDialog : public CDialogImpl<CMyDialog> {

public:

 enum { IDD = IDIDD_MY_DIALOG };

 BEGIN_MSG_MAP(CMyDialog)

// Карта сообщений

 END_MSG_MAP

};

Обратите внимание, что константа IDD описывается в секции public. Если описать её в private– секции, функция базового класса CDialogImpl<>::DoModal не сможет к ней обратиться, что приведёт к ошибке.

Далее полученный класс можно использовать для создания как модальных, так и немодальных диалогов, например:

// Создаём модальный диалог

CMyDialog modal;

modal.DoModal;

//
Создаём немодальный диалог

CMyDialog modeless;

modeless.Create(HWND_DESKTOP);

Класс CAxDialogImpl<>

Класс CAxDialogImpl<> очень похож на предыдущий. Вся разница в том, что вместо функции DialogBoxParam он использует функцию AtlAxDialogBox, а вместо функции CreateDialogParam – функцию AtlAxCreateDialog:

// modal dialogs

int DoModal(HWND hWndParent = ::GetActiveWindow, LPARAM dwInitParam = NULL) {

 ATLASSERT(m_hWnd == NULL);

 _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT<TBase>*)this);

#ifdef _DEBUG

 m_bModal = true;

#endif //_DEBUG

 return AtlAxDialogBox(_Module.GetResourceInstance, MAKEINTRESOURCE(T::IDD),

hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);

}

...

// modeless dialogs

HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) {

 ATLASSERT(m_hWnd == NULL);

 _Module.AddCreateWndData(&m_thunk.cd, (CDialogImplBaseT<TBase>*)this);

#ifdef _DEBUG

 m_bModal = false;

#endif //_DEBUG

 HWND hWnd = AtlAxCreateDialog(_Module.GetResourceInstance, MAKEINTRESOURCE(T::IDD),

hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);

 ATLASSERT(m_hWnd == hWnd);

 return hWnd;

}

Эти функции, в отличие от своих аналогов из Win32 API, могут создавать диалоги, содержащие ActiveX-контролы. Мы не будем рассматривать их реализацию, поскольку тема использования ActiveX-контролов выходит за рамки данной статьи.

Класс CSimpleDialog<>

Чтобы создавать диалоги на базе класса CDialogImpl<>, необходимо каждый раз порождать от него собственные классы. Это довольно утомительно. Класс CSimpleDialog<> предназначен для отображения простейших модальных диалогов, содержащих только статическую информацию и стандартные кнопки, такие как "OK" и "Отмена". Кроме функции DoModal, которая реализована почти так же, как в классе CDialogImpl<>, этот класс предоставляет собственную карту сообщений и обработчики OnInitDialog и OnCloseCmd. Последний вызывается в ответ на нажатие любой кнопки со стандартным идентификатором (IDOK, IDCANCEL, IDABORT, IDRETRY, IDIGNORE, IDYES или IDNO) и закрывает диалог.

Поделиться с друзьями: