Библиотека классов MFC
Элементы управления и диалоги
Диалоги. Знакомство с элементами управления
Диалог (диалоговое окно) представляет собой специальный вид окон, которые предназначены для взаимодействия с пользователем. Обычно они используются для изменения настроек приложения и ввода информации. Например, практически все окна настроек приложения Microsoft Word являются диалогами. Есть два типа диалогов: модальные и немодальные. Наиболее распространены первые. В случае модальных диалогов, при активизации диалога основное окно приложения становится пассивным и перестает реагировать на действия пользователя до тех пор, пока он не закроет диалог. В случае немодальных диалогов, диалог существует независимо от других окон, и основное окно также может быть активизировано.
Взаимодействие между диалогом и пользователем
Взаимодействие между диалогом и пользователем осуществляется с помощью элементов управления. Это особый тип окон для ввода или вывода. Элемент управления принадлежит окну-владельцу, в данном случае – диалогу. Все версии Windows поддерживают некоторый набор стандартных элементов управления, к которым относятся кнопки, контрольные переключатели, селекторные кнопки, списки, поля ввода, комбинированные списки, полосы прокрутки и статические элементы.
Рассмотрим кратко каждый из них:
- Обыкновенная кнопка (push button) – это кнопка, которую пользователь "нажимает" мышью или клавишей Enter, переместив предварительно на нее фокус ввода.
- Контрольный переключатель (check box, флажок) может быть либо выбранным, либо нет. Если в диалоге есть несколько контрольных переключателей, то могут быть выбраны одновременно несколько из них.
- Селекторная кнопка (radio button) – это, почти тоже, что и контрольный переключатель. Отличие состоит в том, что при наличии нескольких кнопок в группе может быть выбрана только одна.
- Список (list box) содержит набор строк, из которого можно выбрать одну или несколько. Широко используется при отображении имен файлов.
- Поле ввода (edit box) – это элемент, позволяющий ввести строку текста.
- Комбинированный список (combo box) представляет собой список со строкой ввода.
- Статический элемент (static control) предназначен для вывода текста или графики, но не для ввода.
Элементы управления способны как генерировать сообщения в ответ на действия пользователя, так и получать их от приложения. В последнем случае сообщения являются, фактически, командами, на которые элемент управления должен отреагировать.
Классы MFC для элементов управления
В MFC содержатся классы для всех стандартных элементов управления. Эти классы описывают сами элементы, а также содержат функции для работы с ними. Их называют классами управления. Они порождаются от класса CWnd. Таким образом, все они обладают характеристиками окна. Ниже приведены основные классы управления:
Класс | Элемент управления |
---|---|
CButton | Кнопки, селекторные кнопки и контрольные переключатели |
CEdit | Поля ввода |
CListBox | Списки |
CComboBox | Комбинированные списки |
CScrollBar | Полосы прокрутки |
CStatic | Статические элементы |
В MFC допускается непосредственное обращение к элементам управления, но на практике это происходит очень редко. Удобнее пользоваться соответствующими классами. Наиболее часто элементы управления используются с диалоговыми окнами, хотя можно создавать и отдельные элементы, расположенные в главном окне.
Диалоги как ресурсы
Диалоги не создаются программно. При необходимости из ресурсов загружаются описания диалогов, и Windows по этому описанию формирует окно и размещает на нем все элементы управления. Диалоги редактируются визуально из ресурсного редактора. Диалог вместе со всеми элементами управления представляет собой один ресурс со своим идентификатором. Кроме того, каждый элемент управления имеет свой идентификатор, который может быть только числовым. Обычно идентификаторы имеют префикс в соответствии с названием данного элемента управления, хотя при желании можно использовать любые идентификаторы.
Класс CDialog
В MFC все диалоги являются экземплярами либо класса CDialog, либо порожденных от него классов. Лишь самые простые диалоги используют непосредственно класс CDialog. В общем же случае, необходимо определять собственный класс. Класс CDialog имеет конструкторы со следующими прототипами:
CDialog::CDialog(LPCSTR ResourceName, CWnd *Owner = 0); CDialog::CDialog(UINT ResourceID, CWnd *Owner = 0); CDialog::CDialog();
Параметр ResourceName или ResourceID определяет идентификатор диалога в ресурсах, строковый или числовой. Параметр Owner – это указатель на окно-собственник, если равен 0, то собственником будет главное окно приложения. Последняя форма конструктора предназначена для создания немодальных диалогов.
Обработка сообщений от диалогов
Все диалоги являются разновидностью окон, поэтому для них используется такой же механизм сообщений, как и для главного окна. Для каждого диалога организуется собственная очередь сообщений, так же точно, как и для главного окна. Когда элемент управления диалога активизируется, диалогу посылается сообщение WM_COMMAND. С этим сообщением передается идентификатор элемента управления. Для обработки сообщений в карту сообщений диалога нужно поместить макрос ON_COMMAND(). Многие элементы управления генерируют также идентификационный код, который позволяет определить, какое действие было произведено с элементом управления. Во многих случаях по этому коду выбирается тот или иной обработчик.
Вызов модального диалога
После того, как объект класса диалога создан, необходимо вызвать член-функцию DoModal(). Результатом вызова будет модальное отображение диалога. Прототип функции следующий:
virtual int CDialog::DoModal();
Функция возвращает код завершения, генерируемый диалогом при закрытии, или -1, если окно не может быть отображено. Если при отображении диалога произошла ошибка, возвращается IDABORT. Функция не завершается, пока диалог не будет закрыт.
Закрытие модального диалога
По умолчанию диалог закрывается при получении сообщения с идентификатором либо IDOK, либо IDCANCEL. Они предопределены и обычно связаны с кнопками подтверждения и отмены. Класс CDialog содержит встроенные обработчики для этих двух случаев, OnOK() и OnCancel(). Их не нужно включать в очередь сообщений диалога. Но, их можно переопределить, что дает возможность программисту управлять закрытием диалога. Для программного закрытия диалога необходимо вызвать член-функцию с прототипом:
void CDialog::EndDialog(int RetCode);
Параметр определяет значение, которое вернет функция DoModal(). Обычно возвращаются значения IDOK или IDCANCEL, другие значения используются редко.
Инициализация диалога
Часто на практике возникает ситуация, когда различные переменные и элементы управления, связанные с диалогом, должны быть инициализированы до того, как диалог будет отображен. Чтобы позволить диалогу выполнить подобные действия, Windows автоматически посылает ему сообщение WM_INITDIALOG в момент создания. При получении такого сообщения MFC автоматически вызывает метод OnInitDialog(), который является стандартным обработчиком, определенным в классе CDialog. Эта функция переопределяется в программе, если необходимо выполнение инициализации. Прототип функции:
virtual BOOL CDialog::OnInitDialog();
Функция вызывается до того, как диалог будет отображен. Она должна возвращать TRUE, чтобы Windows могла передать фокус ввода (т. е. сделать активным) на первый элемент управления в окне. Первым действием в переопределенной функции должен быть вызов функции CDialog::OnInitDialog().
Немодальные диалоги
Немодальные диалоги получают сообщения параллельно с основным окном приложения. То есть, как минимум два окна будут одновременно активными. Поэтому, работа с немодальными диалогами требует больше усилий – должны быть выполнены дополнительные операции. Для создания немодального диалога, необходимо создать "пустой" объект диалога, то есть не связанный с шаблоном из ресурсов. Привязка к ресурсам осуществляется через функцию Create(…). Рассмотрим этот процесс подробнее. Для создания объекта немодального диалога, необходимо использовать конструктор CDialog::CDialog() без параметров. Он объявлен как protected-член класса. Это означает, что он может быть вызван только изнутри члена-функции порожденного класса. Это сделано для того, чтобы программист обязательно определял свой порожденный класс для немодального диалога, и определял в нем дополнительные операции для немодального диалога. Когда экземпляр создан, он привязывается к ресурсам с помощью функций:
BOOL CDialog::Create(LPCSTR ResourceName, CWnd *Owner = 0); BOOL CDialog::Create(UINT ResourceId, CWnd *Owner = 0);
Первый параметр определяет идентификатор диалога в ресурсах. Второй параметр определяет окно-собственник для диалога. Необходимо помнить о том, что объект немодального диалога должен существовать в течение всего времени использования диалога. Функция Create(…) отображает окно и после этого немедленно завершает свою работу. А объект окна должен существовать. В отличие от модальных окон, немодальные не становятся автоматически видимыми при вызове. Чтобы диалог сразу был видимым, необходимо в ресурсном редакторе установить опцию Visible. Или можно использовать функцию ShowWindow(…). Для закрытия немодального диалога, необходимо использовать функцию DestroyWindow(). Это означает, что функции OnCancel() и/или OnOK() должны быть переопределены.
Использование диалога в качестве главного окна
Использование диалога в качестве главного окна часто бывает очень удобным. Реализовать этот случай достаточно просто. Во-первых, необходимо создать диалог в ресурсах. Во-вторых, породить класс главного окна приложения от CDialog. Перед конструктором класса главного окна необходимо вызвать конструктор класса CDialog, и в нем привязать объект к ресурсам, например:
CMainFrame::CMainFrame():CDialog(IDD_MYDIALOG) { //... здесь тело конструктора }
В-третьих, в функции CApp::InitInstance() должен присутствовать следующий код:
// Создаем объект диалогового окна CMainFrame dlgWnd; // Cообщаем MFC адрес окна m_pMainWnd = &dlgWnd; // Отображаем модальный диалог dlgWnd.DoModal(); // Возвратим FALSE, чтобы MFC не пыталась инициировать // очередь сообщений главного окна. return FALSE;
Мы отображаем модальный диалог. Так как при завершении функции DoModal() нам уже не нужна очередь сообщений, мы "обманываем" MFC, делая вид, что инициализация прошла неудачно.