В этой главе мы рассмотрим диалоговые окна. Приложения для Windows часто общаются с пользователем через диалоговые окна. Класс CDialog предоставляет интерфейс для управления диалоговыми окнами. Диалоговый редактор Visual C ++ позволяет легко проектировать диалоговые окна и создавать их ресурсы шаблона диалога.
-
Создание объекта диалога является двухфазной операцией –
-
Построить объект диалога.
-
Создайте диалоговое окно.
-
Создание объекта диалога является двухфазной операцией –
Построить объект диалога.
Создайте диалоговое окно.
Давайте рассмотрим простой пример, создав новый проект Win32.
Шаг 1 – Откройте Visual Studio и выберите пункт меню Файл → Создать → Проект.
Шаг 2 – Теперь вы можете увидеть диалоговое окно New Project.
Шаг 3 – На левой панели выберите Шаблоны → Visual C ++ → Win32.
Шаг 4 – В средней панели выберите Win32 Project.
Шаг 5 – Введите имя проекта «MFCDialogDemo» в поле «Имя» и нажмите «ОК» для продолжения. Вы увидите следующий диалог.
Шаг 6 – Нажмите Далее.
Шаг 7 – Выберите параметры, показанные в диалоговом окне, указанном выше, и нажмите Готово.
Шаг 8 – Пустой проект создан.
Шаг 9 – Чтобы сделать его проектом MFC, щелкните проект правой кнопкой мыши и выберите «Свойства».
Шаг 10 – В левом разделе нажмите Свойства конфигурации → Общие.
Шаг 11 – Выберите параметр «Использовать MFC в общей библиотеке DLL» в разделе «Параметры проекта по умолчанию» и нажмите «ОК».
Шаг 12 – Добавьте новый исходный файл.
Шаг 13 – Щелкните правой кнопкой мыши по вашему проекту и выберите Добавить → Новый элемент.
Шаг 14 – В разделе «Шаблоны» нажмите «Файл C ++» (.cpp)
Шаг 15 – Установите имя в качестве примера и нажмите «Добавить».
Шаг 16. Чтобы создать приложение, нам нужно добавить класс и извлечь его из CWinApp MFC.
#include <afxwin.h> class CExample : public CWinApp { public: BOOL InitInstance(); };
Создание диалогового окна
Шаг 1. Чтобы создать диалоговое окно, щелкните правой кнопкой мыши папку Resource Files в обозревателе решений и выберите Add → Resource.
Шаг 2 – В диалоговом окне «Добавить ресурс» выберите «Диалог» и нажмите «Создать».
Шаг 3 – Диалоговое окно требует некоторой подготовки, прежде чем фактически его создавать программно.
Шаг 4 – Сначала можно вручную создать диалоговое окно в виде текстового файла (в файле ресурсов).
Шаг 5 – Теперь вы можете увидеть файл MFCDialogDemo.rc, созданный в разделе Resource Files.
Шаг 6 – Файл ресурсов открыт в конструкторе. То же самое можно открыть как текстовый файл. Щелкните правой кнопкой мыши файл ресурса и выберите «Открыть с помощью».
Шаг 7 – Выберите редактор исходного кода (текст) и нажмите кнопку Добавить.
Шаг 8 – Вернитесь к конструктору, щелкните правой кнопкой мыши диалоговое окно и выберите «Свойства».
Шаг 9 – Вам нужно выбрать из множества вариантов.
Шаг 10 – Как и большинство других элементов управления, диалоговое окно должно быть идентифицировано. Идентификатор (ID) диалогового окна обычно начинается с IDD_. Давайте изменим ID на IDD_EXAMPLE_DLG.
Расположение диалога
Диалоговое окно должно быть «физически» расположено в приложении. Поскольку диалоговое окно обычно создается в качестве родительского элемента для других элементов управления, его расположение зависит от его отношения к родительскому окну или к рабочему столу.
Если вы посмотрите и окно свойств, вы увидите два поля, X Pos и Y Pos.
-
X – расстояние от левой границы монитора до левой границы диалогового окна.
-
Y – расстояние от верхней границы монитора до верхней границы диалогового окна.
X – расстояние от левой границы монитора до левой границы диалогового окна.
Y – расстояние от верхней границы монитора до верхней границы диалогового окна.
По умолчанию эти поля установлены на ноль. Вы также можете изменить, как показано выше.
Если вы укажете эти два измерения как 0, левая и верхняя границы диалогового окна будут установлены так, что объект появится в центре по центру экрана.
Диалоговое окно Размеры
Размеры диалогового окна относятся к его ширине и высоте. Вы можете изменить ширину и высоту с помощью мыши в окне дизайнера.
Вы можете увидеть изменения ширины и высоты в строке состояния.
Методы диалоговых окон
Базовый класс, используемый для отображения диалоговых окон на экране, – это класс CDialog. Чтобы создать диалоговое окно, нам нужно извлечь класс из CDialog. Сам класс CDialog предоставляет три конструктора:
CDialog(); CDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);
Давайте создадим еще один класс CExampleDlg и выведем его из CDialog. Мы реализуем его конструктор по умолчанию, как показано в следующем коде.
class CExampleDlg : public CDialog { public: enum { IDD = IDD_EXAMPLE_DLG }; CExampleDlg(); ~CExampleDlg(); }; CExampleDlg::CExampleDlg():CDialog(CExampleDlg::IDD) { } CExampleDlg::~CExampleDlg() { }
Нам нужно создать этот диалог в методе CExample :: InitInstance (), как показано в следующем коде.
BOOL CExample::InitInstance() { CExampleDlg myDlg; m_pMainWnd = &myDlg; return TRUE; }
Модальные диалоговые окна
Существует два типа диалоговых окон – немодальное и модальное . Модальные и немодальные диалоговые окна отличаются процессом, используемым для их создания и отображения.
Немодальное диалоговое окно
-
Для немодального диалогового окна вы должны предоставить свой собственный общедоступный конструктор в вашем диалоговом классе.
-
Чтобы создать немодальное диалоговое окно, вызовите ваш общедоступный конструктор, а затем вызовите функцию Create member объекта диалога, чтобы загрузить ресурс диалога.
-
Вы можете вызвать Create во время или после вызова конструктора. Если ресурс диалога имеет свойство WS_VISIBLE, диалоговое окно появляется немедленно.
-
Если нет, вы должны вызвать его функцию-член ShowWindow.
Для немодального диалогового окна вы должны предоставить свой собственный общедоступный конструктор в вашем диалоговом классе.
Чтобы создать немодальное диалоговое окно, вызовите ваш общедоступный конструктор, а затем вызовите функцию Create member объекта диалога, чтобы загрузить ресурс диалога.
Вы можете вызвать Create во время или после вызова конструктора. Если ресурс диалога имеет свойство WS_VISIBLE, диалоговое окно появляется немедленно.
Если нет, вы должны вызвать его функцию-член ShowWindow.
Модальный диалог
-
Чтобы создать модальное диалоговое окно, вызовите любой из двух открытых конструкторов, объявленных в CDialog.
-
Затем вызовите функцию- член DoModal объекта диалога, чтобы отобразить диалоговое окно и управлять взаимодействием с ним, пока пользователь не выберет OK или Отмена.
-
Это управление DoModal делает модальное диалоговое окно. Для модальных диалоговых окон DoModal загружает ресурс диалога.
Чтобы создать модальное диалоговое окно, вызовите любой из двух открытых конструкторов, объявленных в CDialog.
Затем вызовите функцию- член DoModal объекта диалога, чтобы отобразить диалоговое окно и управлять взаимодействием с ним, пока пользователь не выберет OK или Отмена.
Это управление DoModal делает модальное диалоговое окно. Для модальных диалоговых окон DoModal загружает ресурс диалога.
Шаг 1 – Чтобы отобразить диалоговое окно как модальное, в событии CExample :: InitInstance () вызовите метод DoModal () с помощью вашей диалоговой переменной –
BOOL CExample::InitInstance() { CExampleDlg myDlg; m_pMainWnd = &myDlg; myDlg.DoModal(); return TRUE; }
Шаг 2 – Вот полная реализация файла Example.cpp.
#include <afxwin.h> #include "resource.h" class CExample : public CWinApp { public: BOOL InitInstance(); }; class CExampleDlg : public CDialog { public: enum { IDD = IDD_EXAMPLE_DLG }; CExampleDlg(); ~CExampleDlg(); }; CExampleDlg::CExampleDlg():CDialog(CExampleDlg::IDD) { } CExampleDlg::~CExampleDlg() { } BOOL CExample::InitInstance() { CExampleDlg myDlg; m_pMainWnd = &myDlg; myDlg.DoModal(); return TRUE; } CExample MyApp;
Шаг 3 – Когда приведенный выше код скомпилирован и выполнен, вы увидите следующее диалоговое окно.
Приложения на основе диалогов
Microsoft Visual Studio предоставляет более простой способ создания приложения, основанного главным образом на диалоговом окне. Вот шаги для создания базового проекта диалога, используя шаблоны проектов, доступные в Visual Studio –
Шаг 1 – Откройте Visual Studio и выберите пункт меню Файл → Создать → Проект. Вы можете увидеть диалоговое окно New Project.
Шаг 2 – На левой панели выберите Шаблоны → Visual C ++ → MFC.
Шаг 3 – В средней панели выберите Приложение MFC.
Шаг 4 – Введите имя проекта «MFCModalDemo» в поле «Имя» и нажмите «ОК» для продолжения. Вы увидите следующее диалоговое окно.
Шаг 5 – Нажмите Далее.
Шаг 6 – Выберите параметры, показанные в диалоговом окне выше, и нажмите Далее.
Шаг 7 – Отметьте все параметры, которые вы выбрали в диалоговом окне, такие как «Развернуть и свернуть поля», и нажмите «Далее».
Шаг 8 – Нажмите Далее.
Шаг 9 – Он сгенерирует эти два класса. Вы можете изменить название классов и нажать «Готово».
Шаг 10. Теперь вы видите, что мастер MFC создает это диалоговое окно и файлы проекта по умолчанию.
Шаг 11 – Когда вы запустите это приложение, вы увидите следующий вывод.
-
Диалоговые окна
При
разработке Windows-приложений часто
возникает необходимость вывода различных
сообщений при обработки разных событий.
Чаще всего сообщения выводятся в
специальные диалоговые окна.
Диалоговое
окно — это форма, обладающая некоторыми
специальными характеристиками. Первая
отличительная черта большинства
диалоговых окон — то, что их размер
изменять нельзя. Кроме того, в диалоговых
окнах обычно не используются элементы
управления,
помещаемые в заголовке обычных
форм: ControlBox, MinimizeBox и MaximizeBox.
Для пользователя диалоговое
окно в
противоположность обычным является
практически неизменяемым.
Диалоговые
окна бывают модальные и немодальные.
Если приложение открывает
модальное окно, то работа приложения
блокируется до тех пор, пока не будет
закрыто модальное окно. Немодальные
окна могут работать одновременно с
породившим их главным окном приложения.
Такие окна часто используются для
«плавающих» инструментальных
панелей, настройки различных параметров
приложения, причем отсутствие модальности
позволяет использовать в приложении
измененные параметры, не закрывая окна
настройки этих параметров.
Windows предоставляет
множество функций, сообщений и
предопределенных элементов управления,
которые помогают создавать и управлять
диалоговыми окнами, таким образом,
облегчая процесс разработки интерфейса
пользователя для прикладной программы.
Окно
сообщения (message
box)
— специальное диалоговое окно, которое
прикладная программа может использовать,
чтобы показывать сообщения и приглашение
для обычного ввода данных. Окно сообщения
обычно содержит текстовое сообщение и
одну или большее количество кнопок.
Прикладная программа создает окно
сообщения, используя специальный класс
MessageBox,
определяя текст сообщения, заголовок,
число и типы кнопок для показа.
Окно
сообщения — модальное диалоговое окно
и
Windows создает
его, используя те же самые внутренние
функции, что и DialogBox.
Для
отображения диалогового окна MessageBox
используется метод Show,
передав ему через параметр
текст сообщения. По умолчанию в окне
устанавливается кнопка ОК. Например:
MessageBox::Show(«Hi!
Student»);
Выполнение этой
инструкции приведет к открытию следующего
окна:
Рисунок
3.4. – Окно сообщений
Вторым параметром
в окне сообщений задается заголовок
окна:
MessageBox::Show(«Hi!
Student!», «Welcome»);
Окно с заголовком
приведено на рисунке 3.5.
Рисунок
3.5. – Окно сообщений с заголовком
С помощью
третьего параметра можно указать,
какие кнопки необходимо расположить в
окне MessageBox.
Этот параметр задается
константами из перечисления
MessageBoxButtons
(Таблица 1).
Таблица 1
Константа |
Кнопки, |
ОК |
OK |
OKCancel |
OK, |
YesNo |
Yes, |
YesNoCancel |
Yes, |
RetryCancel |
Retry, |
AbortRetryIgnore |
Abort, |
Например,
мы хотим выводить окно подтверждения
на завершение работы приложения. В этом
случае выберем набор кнопок Yes
и No.
Метод MessageBox.Show может
вернуть одно из нескольких значений
перечисления DialogResult ( Таблица
2).
Таблица |
|
Константа |
Кнопка, |
Abort |
Abort |
Cancel |
Cancel |
Ignore |
Ignore |
No |
No |
None |
Модальное |
OK |
OK |
Retry |
Retry |
Yes |
Yes |
Метод MessageBox::Show()
возвращает результат выбора пользователя,
который должен быть проанализирован и
в зависимости от выбора приложение
должно быть закрыто или нет. Тогда текст
программы примет вид:
System::Windows::Forms::DialogResult
rez=
MessageBox::Show(«Закрыть
приложение?»,»Завершение работы»,
MessageBoxButtons::YesNo);
if
(rez==System::Windows::Forms::DialogResult::Yes)this->Close();
Вид окна подтверждения
приведен на рисунке 3.6.
Рисунок
3.6 – Окно подтверждения
С помощью
четвертого параметра
метода MessageBox::Show можно
выбрать один из нескольких значков для
расположения в левой части диалогового
окна. Он задается в виде константы
константы перечисления MessageBoxIcon ( таблица
3).
Таблица |
|
Константа |
Значок |
Asterisk, |
|
Error, |
|
Exclamation, |
|
Question |
|
None |
Значок |
Добавим в предыдущий
пример создания окна подтверждения
вывод значка вопроса:
System::Windows::Forms::DialogResult
rez= MessageBox::Show(«Закрыть
приложение?»,»Завершение
работы»,
MessageBoxButtons::YesNo,
MessageBoxIcon::Question);
Получим
следующий
вид
окна:
Рисунок
3.7 — Окно подтверждения с выводом
вопросительной
пиктограммы
Диалоговое
окно можно
создать не только на основе класса MessageBox,
но и с использованием Windows -формы.
Рассмотрим примеры проектирования
простейших Windows-приложений.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Диалоговые окна
Диалоговые окна
Кроме окон программ и папок, пользователям Windows часто приходится иметь дело с различными диалоговыми окнами, которые служат для взаимодействия пользователя с операционной системой и прикладными программами. С их помощью можно изменять параметры работы системы и давать команды для выполнения определенных действий.
Диалоговые окна обычно имеют упрощенный вид и могут содержать несколько стандартных элементов управления. Рассмотрим для примера окно настройки даты и времени. Чтобы его открыть, щелкните кнопкой мыши на изображении часов на Панели задач, затем в появившемся окне перейдите по ссылке Изменение настройки даты и времени (рис. 1.13).
Рис. 1.13. Окно настройки даты и времени
В различных диалоговых окнах можно найти следующие элементы.
? Вкладка. Окна с большим количеством элементов управления разделены на несколько вкладок. Вкладку можно рассматривать как одну страницу многостраничного окна (см. рис. 1.13). Например, окно настройки даты и времени содержит три вкладки: Дата и время, Дополнительные часы, Время Интернета. Чтобы перейти на другую вкладку, нужно щелкнуть кнопкой мыши на ее имени в верхней части окна.
? Кнопка. Щелчок на кнопке позволяет выполнить действие, указанное в ее названии. В нижней части окна настройки даты и времени (см. рис. 1.13) есть три кнопки: ОК, Отмена и Применить. Эти кнопки вы будете встречать довольно часто в разных диалоговых окнах, поэтому рассмотрим их назначение подробнее:
• ОК – закрывает диалоговое окно и сохраняет все выполненные изменения;
• Отмена – закрывает окно без сохранения изменений;
• Применить – сохраняет изменения без закрытия диалогового окна.
На некоторых кнопках может отображаться значок в виде щита, например данный элемент есть на кнопке Изменить дату и время (см. рис. 1.13). Это значит, что для выполнения данной команды у вас должны быть права администратора компьютера. После щелчка на кнопке придется подтвердить команду в окне службы контроля учетных записей (см. урок. 8.1).
? Числовое поле. Этот элемент служит для ввода числовых значений. Найти числовое поле можно в окне настройки экранной заставки. Для этого щелкните правой кнопкой мыши на свободном участке Рабочего стола, выполните в контекстном меню команду Персонализация и в появившемся окне перейдите по ссылке Экранная заставка. В окне Параметры экранной заставки (рис. 1.14) есть числовое поле, в котором можно задать время появления заставки при простое компьютера. Введите числовое значение с клавиатуры или же щелкните на кнопках со стрелками.
Рис. 1.14. Окно настройки экранной заставки
? Раскрывающийся список. Этот элемент управления служит для выбора одного варианта из имеющихся. Например, в окне настройки экранной заставки (см. рис. 1.14) вы можете выбрать другую заставку из имеющегося списка. Для этого необходимо щелкнуть кнопкой мыши на стрелке в правой части списка, а затем на названии нужной заставки.
? Текстовое поле. Служит для ввода текстовой информации и обычно имеет вид прямоугольной рамки, в которую вводят текст после щелчка кнопкой мыши на ней. Чтобы увидеть текстовое поле, выберите заставку Объемный текст в окне настройки экранной заставки и нажмите кнопку Параметры. В появившемся окне (рис. 1.15) вы сможете изменить текст заставки в соответствующем текстовом поле.
Рис. 1.15. Окно Параметры заставки «Объемный текст»
? Флажок. Данный элемент имеет вид маленького квадратного окошка с названием. Флажок может находиться в двух положениях – установленном и снятом. Для изменения положения флажка нужно щелкнуть на нем кнопкой мыши. Например, в окне Параметры заставки «Объемный текст» (см. рис. 1.15) флажок Отображать световые блики установлен, а флажок Выбрать отражение – снят.
? Переключатель. Подобно списку, позволяет выбрать одно из нескольких возможных значений параметров. Переключатель представляет собой группу круглых окошек со значениями, из которых можно выбрать только одно. Для выбора нужного значения щелкните кнопкой мыши на соответствующем окошке или самом значении.
В окне Параметры заставки «Объемный текст» (см. рис. 1.15) есть две группы переключателей. Первая группа (Текст) позволяет выбрать текст или время для заставки, а вторая (Поверхность) – один из трех вариантов поверхности. Вы можете изменить любые параметры этой заставки, после чего следует нажать кнопку ОК для подтверждения ваших действий. Чтобы увидеть изменения, нажмите кнопку Просмотр.
? Регулятор. Служит для плавного изменения определенного параметра путем перетаскивания ползунка с помощью мыши. В рассмотренном окне параметров заставки (см. рис. 1.15) также есть несколько регуляторов – Разрешение, Размер и Скорость вращения.
Все современные компьютеры оборудованы звуковыми платами и колонками. В области уведомлений Панели задач обычно есть значок динамика, щелчок кнопкой мыши на котором открывает регулятор громкости. Чтобы изменить громкость, используя мышь, перетащите ползунок вверх или вниз.
Приведу несколько важных замечаний по работе с диалоговыми окнами.
? В этой книге вы будете встречаться с описанием различных диалоговых окон. Все они будут состоять из всевозможных комбинаций рассмотренных выше элементов.
? Вы можете сколько угодно практиковаться в изменении параметров экранных заставок, но с другими диалоговыми окнами следует быть осторожнее: не зная, к чему может привести изменение того или иного параметра, вы можете серьезно нарушить работу системы.
Данный текст является ознакомительным фрагментом.
Читайте также
Окна
Окна
Любое действие на компьютере (работа с программой, настройка системы, подключение к Сети) пользователь выполняет в окне. Окно – это ограниченное пространство прямоугольной формы на экране, в котором отображается содержимое объекта, запрошенного пользователем.Окна
Другие диалоговые окна
Другие диалоговые окна
В Windows XP присутствуют не только диалоговые окна и мастера для работы с сетью — есть и много других диалоговых окон, некоторые стоят того, чтобы их рассмотреть. Например, существует возможность открытия диалогового окна Сертификаты,
Глава 4 Контекстное меню и диалоговые окна
Глава 4 Контекстное меню и диалоговые окна
В предыдущих главах говорилось о том, как управлять окнами, запускать программы, создавать, сохранять и редактировать документы. В этой главе речь пойдет о контекстных меню и диалоговых окнах. Эти элементы интерфейса
Динамические диалоговые окна
Динамические диалоговые окна
Динамическими называются диалоговые окна, которые создаются на основе файлов .ui, сделанных в Qt Designer, во время выполнения приложения. Вместо преобразования файла .ui компилятором uic в программу на С++ мы можем загрузить этот файл на этапе
6.1. Встроенные диалоговые окна
6.1. Встроенные диалоговые окна
Диалоговые окнаВ VBA существуют две возможности создания диалоговых окон, позволяющих вести интерактивный диалог с пользователями.Окно сообщений MsgBox выводит простейшие сообщения для пользователя, а окно ввода InputBox обеспечивает ввод
Окна
Окна
Для построения окна активизируйте категорию Geometry (Геометрия)
вкладки Create (Создание) командной панели и в раскрывающемся cписке подкатегорий (там, где написано Standard Primitives (Стандартные примитивы)) выберите группу объектов Windows (Окна). В свитке Object Type (Тип объекта)
Стандартные диалоговые окна
Стандартные диалоговые окна
ChooseColor
Функция ChooseColor создает стандартное диалоговое окно выбора цвета. BOOL ChooseColor ( LPCHOOSECOLOR lpcc // указатель на структуру с инициализирующими данными ); Параметры lpcc — указатель на структуру типа CHOOSECOLOR , которая содержит информацию,
Диалоговые окна
Диалоговые окна
CreateDialog
Макрос CreateDialog создает немодальное диалоговое окно из ресурса — шаблона диалогового окна. Макрос CreateDialog использует функцию CreateDialogParam . HWND CreateDialog ( HINSTANCE hInstance , // дескриптор экземпляра приложения LPCTSTR lpTemplate , // идентифицирует имя шаблона диалогового
2.4. Стандартные диалоговые окна Windows
2.4. Стандартные диалоговые окна Windows
Теперь рассмотрим, как можно только при помощи функций Windows API вызывать некоторые распространенные диалоговые окна. Чтобы использовать API-функции и структуры с информацией для этих диалоговых окон, необходимо подключить следующие
Окна
Окна
Команд для вставки различных окон в план здания в программе также немало. Сам процесс добавления окна в конструкцию ничем не отличается от добавления двери, поэтому и настройки окон разных типов во многом напоминают настройки дверей. Вызвать окно с настройками для
Слуховые окна и окна в крыше
Слуховые окна и окна в крыше
Фактически наш дом, с конструктивной точки зрения, принял уже вполне законченный вид. Однако попробуем добавить к нему еще некоторые элементы, которые хоть и не обязательны, но нередко встречаются в различных коттеджах. Сначала построим одно
Диалоговые окна
Диалоговые окна
В диалоговых окнах обычно выводится код ошибки и ее краткое описание (рис. 6.1). Далеко не всегда короткого описания хватает, чтобы понять, что же случилось, и устранить причину ошибки. А иногда описание непонятно, потому что оно на английском (в англоязычных
1.4. Окна
1.4. Окна
Mac OS X, как и Windows, является операционной системой с оконным интерфейсом, т. е. взаимодействие пользователя с системой осуществляется с помощью окон, а не в режиме командной строки, как, например, в операционных системах MS DOS или FreeBSD. Поэтому окно является основным и
Урок 1.3. Контекстное меню и диалоговые окна
Урок 1.3. Контекстное меню и диалоговые окна
Контекстное меню
Контекстное меню вызывается щелчком правой кнопки мыши на каком-либо объекте. В нем расположен список часто используемых команд для конкретного объекта. Для примера щелкните правой кнопкой мыши на Рабочем
Диалоговые окна
Диалоговые окна
Кроме окон программ и папок, пользователям Windows часто приходится иметь дело с различными диалоговыми окнами, которые служат для взаимодействия пользователя с операционной системой и прикладными программами. С их помощью можно изменять параметры работы
In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.
1. Introduction
When writing pure Win32 programs, usually you see tutorials showing how to use “raw” windows, by filling a WNDCLASSEX
structure, calling RegisterClassEx
and then CreateWindowEx
. This is explained in detail in Charles Petzold’s classic Programming Windows book – a must-have for any Win32 programmer, let me say.
But sometimes you don’t need to create a new window entirely from scratch, a simple dialog box would fit your needs.
In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. A dialog box resource can be quickly created – with labels, editboxes, and buttons – using any resource editor. Here I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.
I’ll use pure Win32 C code to keep things as simple as possible: no MFC, no ATL, no WTL, or whatever. I’ll also use the TCHAR
functions (declared in tchar.h, more information here) to make the code portable with ANSI and Unicode, and only functions that are both x86 and x64 compatible.
1.1. Program Structure
Our program will be composed of three files:
- C source file – the source code we’ll effectively write, and the central theme of this article;
- RC resource script – describes the dialog box resources, easily created by Visual Studio or any resource editor, or even by hand, and compiled with a resource compiler; and
- H resource header – simply the macro constants used in the RC file to identify the resources, usually created automatically together with the RC script.
2. The Dialog Box
Before writing the C source code, we’ll create an empty project and add a dialog box resource to it. When doing so, a resource script is created, containing the dialog box code. Let’s start a new project:
Choose “Visual C++” and “Win32” from the tree in the left, then “Win32 project”, and give a name to it. Pay attention to the directory you are saving it. Then click OK:
Now choose “Windows application” and “Empty project”. When creating an empty project, Visual Studio will create no files for us, and this is important because here we want to create a pure Win32 program, with no additional libraries. Then, click “Finish”:
Now, let’s add the dialog box. In the Solution Explorer window – if you can’t see it, enable it in the “View” menu – right-click the project name and choose “Add”, “Resource”:
Here you can see a couple of resource items whose script can be generated automatically by Visual Studio. We’ll use just the dialog box, so choose “Dialog” and click “New”:
Once done, you should see your dialog in the resource editor, where you can add controls – like editboxes, buttons, and labels – by just using the mouse, positioning and arranging them really quick – much quicker than you would do with a “raw window” application, where you must deal with the code directly. My dialog looks like this:
At this point, we have a resource script and a resource header, they can be seen in the Solution Explorer. Now it’s time to write the source code to bring this dialog box alive.
3. The Source Code
Let’s add an empty source file to our project. In the Solution Explorer, right-click the “Source Files” folder, then “Add”, “New Item”. Then give any name to the file, like “main.c”.
In Visual Studio, by default, the source files will be compiled according to the file extension: C files compiled as plain C; and CPP, CXX (and some others) compiled as C++. Here we’ll write C code, but it can also be compiled as C++, so the file extension can be any of those cited. Particularly, I used the C extension, to make it clear it’s a plain C program.
Our C source will have only two functions:
WinMain
– the program entry point, which will have the main program loop; andDialogProc
– the dialog box procedure, which will process the dialog messages.
Let’s start writing the code with the normal Win32 entry point function (the TCHAR
version of it):
#include <Windows.h> #include <tchar.h> #include "resource.h" int _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPCTSTR lpCmdLine, int nCmdShow) { return 0; }
4. Dialog Creation and Message Loop
The dialog will be created inside the WinMain
function with the CreateDialogParam
function (instead of CreateWindowEx
), and there is no window class registration. Then, we make it visible with a call to ShowWindow
:
HWND hDlg; hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow);
IDD_DIALOG1
is the resource identifier to our dialog box, declared in resource.h. DialogProc
is our dialog box procedure, which will handle all dialog messages – I’ll show it later on.
Then it follows the main program message loop. It’s the heart of any Win32 program – see it as the bridge between the operational system and your program. It also exists in common “raw window” programs, although slightly different from this. Here, the message loop is specifically to deal with a dialog box as the main window:
BOOL ret; MSG msg; while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
The IsDialogMessage
function immediately forwards the message to our dialog box procedure if it belongs to it. Otherwise, the message enters regular handling. More information about the message loop can be found here.
There is a possibility to bypass this program loop (not writing it), as explained by Iczelion in the 10th lesson of his wonderful Win32 Assembly article series. However, by doing so, we have less control: we cannot put any verification in the loop, like accelerator handling, for example. So, let’s keep the loop in our code.
4.1. Enabling Visual Styles
In order to get the common controls 6 visual styles, introduced with Windows XP, you must not only call InitCommonControls
(declared in CommCtrl.h), but also embed a manifest XML file into your code. Fortunately, there is a handy trick you can use in the Visual C++ compiler, which I learned from Raymond Chen’s blog. Just add this to your code:
#pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"")
This will generate and embed the XML manifest file automatically, and you’ll never worry about it again.
To call InitCommonControls
, you must statically link your program to ComCtl32.lib, and this can be accomplished with a #pragma comment
directive as well:
#pragma comment(lib, "ComCtl32.lib")
4.2. Our WinMain
So far, this is our complete WinMain
function (without the dialog box procedure yet):
#include <Windows.h> #include <CommCtrl.h> #include <tchar.h> #include "resource.h" #pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"") #pragma comment(lib, "ComCtl32.lib") int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow) { HWND hDlg; MSG msg; BOOL ret; InitCommonControls(); hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow); while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; }
5. Dialog Box Procedure
The dialog procedure is responsible for handling all program messages, responding to all events. It starts like this:
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return FALSE;
}
Windows calls this function for every program message. If we return FALSE
, it means Windows can carry out the default processing for the message, because we’re not interested in it; if we return TRUE
, we tell Windows we’ve actually processed the message. This is slightly different from the “raw” window message handling through WndProc
, where you return a call to the DefWindowProc
function. Here, we must not call DefWindowProc
, just return FALSE
.
So, we’ll write only the handling of messages that are interesting to us. Among the most commonly used messages, we have WM_INITDIALOG
, WM_COMMAND
, and WM_SIZE
. But to build a minimal functional program, we need only two:
switch(uMsg) { case WM_CLOSE: return TRUE; case WM_DESTROY: return TRUE; }
Notice we don’t need to handle the WM_PAINT
message with dialog boxes.
5.1. The Minimal Message Handling
WM_CLOSE
is called just prior to window closing. If you want to ask the user if he really wants to close the program, here is the place to put this check. To close the window, we call DestroyWindow
– if we don’t call it, the window won’t be closed.
So here’s the message handling, also prompting the user. If you don’t need to prompt the user, just omit the MessageBox
check and call DestroyWindow
directly. And don’t forget to return TRUE
here, whether you close the window or not:
case WM_CLOSE: if(MessageBox(hDlg, TEXT("Close the window?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } return TRUE;
Finally, we must handle the WM_DESTROY
message, telling Windows we want to quit the main program thread. We do this by calling the PostQuitMessage
function:
case WM_DESTROY: PostQuitMessage(0); return TRUE;
The WM_DESTROY
message is also the best place to free resources that were allocated by the program and are still waiting to be deallocated – it’s final cleanup time. But don’t forget to do the cleanup before calling PostQuitMessage
.
5.2. Closing on ESC
An interesting feature of the dialog boxes is that they can be easily programmed to be closed when the user hits the ESC key, and it can also be done when the dialog box is the main window as well. To do so, we must handle the WM_COMMAND
message and wait for the IDCANCEL
identifier, which comes in the low word of the WPARAM
argument, and that’s what we do:
case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: SendMessage(hDlg, WM_CLOSE, 0, 0); return TRUE; } break;
The IDCANCEL
identifier is declared in WinUser.h, which is included in Windows.h, so it’s always available.
Notice that when handling IDCANCEL
, we send a WM_CLOSE
message to our dialog window, which causes the dialog procedure to be called again with the WM_CLOSE
message that we previously coded, so the user will be prompted if he wants to close the window (because that’s the way we coded it).
6. The Final Program
So here is our final program. It’s the C source code for a minimally functional Win32 dialog based program, with the message loop and visual styles properly enabled, just ready to go. You can keep this to use as the skeleton for any Win32 dialog based program.
#include <Windows.h> #include <CommCtrl.h> #include <tchar.h> #include "resource.h" #pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"") #pragma comment(lib, "ComCtl32.lib") INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: SendMessage(hDlg, WM_CLOSE, 0, 0); return TRUE; } break; case WM_CLOSE: if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } return TRUE; case WM_DESTROY: PostQuitMessage(0); return TRUE; } return FALSE; } int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow) { HWND hDlg; MSG msg; BOOL ret; InitCommonControls(); hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow); while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; }
7. Further Organization
Usually, when your program grows in complexity, you’ll end up with a huge DialogProc
stuffed with code, and therefore very painful to maintain. A useful approach to this is the use of function calls to each message — the famous subroutines. It’s specially handy because it isolates the logic of the code, you can see clearly each part of the program, giving you the notion of responding to events. For example, our program could have two dedicated functions:
void onCancel(HWND hDlg) { SendMessage(hDlg, WM_CLOSE, 0, 0); } void onClose(HWND hDlg) { if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } }
And it would allow us to rewrite our DialogProc
like this:
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: onCancel(hDlg); return TRUE; } break; case WM_CLOSE: onClose(hDlg); return TRUE; case WM_DESTROY: PostQuitMessage(0); return TRUE; } return FALSE; }
History
- 20th July, 2011: Initial version
This article, along with any associated source code and files, is licensed under A Public Domain dedication
This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.
In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.
1. Introduction
When writing pure Win32 programs, usually you see tutorials showing how to use “raw” windows, by filling a WNDCLASSEX
structure, calling RegisterClassEx
and then CreateWindowEx
. This is explained in detail in Charles Petzold’s classic Programming Windows book – a must-have for any Win32 programmer, let me say.
But sometimes you don’t need to create a new window entirely from scratch, a simple dialog box would fit your needs.
In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. A dialog box resource can be quickly created – with labels, editboxes, and buttons – using any resource editor. Here I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.
I’ll use pure Win32 C code to keep things as simple as possible: no MFC, no ATL, no WTL, or whatever. I’ll also use the TCHAR
functions (declared in tchar.h, more information here) to make the code portable with ANSI and Unicode, and only functions that are both x86 and x64 compatible.
1.1. Program Structure
Our program will be composed of three files:
- C source file – the source code we’ll effectively write, and the central theme of this article;
- RC resource script – describes the dialog box resources, easily created by Visual Studio or any resource editor, or even by hand, and compiled with a resource compiler; and
- H resource header – simply the macro constants used in the RC file to identify the resources, usually created automatically together with the RC script.
2. The Dialog Box
Before writing the C source code, we’ll create an empty project and add a dialog box resource to it. When doing so, a resource script is created, containing the dialog box code. Let’s start a new project:
Choose “Visual C++” and “Win32” from the tree in the left, then “Win32 project”, and give a name to it. Pay attention to the directory you are saving it. Then click OK:
Now choose “Windows application” and “Empty project”. When creating an empty project, Visual Studio will create no files for us, and this is important because here we want to create a pure Win32 program, with no additional libraries. Then, click “Finish”:
Now, let’s add the dialog box. In the Solution Explorer window – if you can’t see it, enable it in the “View” menu – right-click the project name and choose “Add”, “Resource”:
Here you can see a couple of resource items whose script can be generated automatically by Visual Studio. We’ll use just the dialog box, so choose “Dialog” and click “New”:
Once done, you should see your dialog in the resource editor, where you can add controls – like editboxes, buttons, and labels – by just using the mouse, positioning and arranging them really quick – much quicker than you would do with a “raw window” application, where you must deal with the code directly. My dialog looks like this:
At this point, we have a resource script and a resource header, they can be seen in the Solution Explorer. Now it’s time to write the source code to bring this dialog box alive.
3. The Source Code
Let’s add an empty source file to our project. In the Solution Explorer, right-click the “Source Files” folder, then “Add”, “New Item”. Then give any name to the file, like “main.c”.
In Visual Studio, by default, the source files will be compiled according to the file extension: C files compiled as plain C; and CPP, CXX (and some others) compiled as C++. Here we’ll write C code, but it can also be compiled as C++, so the file extension can be any of those cited. Particularly, I used the C extension, to make it clear it’s a plain C program.
Our C source will have only two functions:
WinMain
– the program entry point, which will have the main program loop; andDialogProc
– the dialog box procedure, which will process the dialog messages.
Let’s start writing the code with the normal Win32 entry point function (the TCHAR
version of it):
#include <Windows.h> #include <tchar.h> #include "resource.h" int _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPCTSTR lpCmdLine, int nCmdShow) { return 0; }
4. Dialog Creation and Message Loop
The dialog will be created inside the WinMain
function with the CreateDialogParam
function (instead of CreateWindowEx
), and there is no window class registration. Then, we make it visible with a call to ShowWindow
:
HWND hDlg; hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow);
IDD_DIALOG1
is the resource identifier to our dialog box, declared in resource.h. DialogProc
is our dialog box procedure, which will handle all dialog messages – I’ll show it later on.
Then it follows the main program message loop. It’s the heart of any Win32 program – see it as the bridge between the operational system and your program. It also exists in common “raw window” programs, although slightly different from this. Here, the message loop is specifically to deal with a dialog box as the main window:
BOOL ret; MSG msg; while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
The IsDialogMessage
function immediately forwards the message to our dialog box procedure if it belongs to it. Otherwise, the message enters regular handling. More information about the message loop can be found here.
There is a possibility to bypass this program loop (not writing it), as explained by Iczelion in the 10th lesson of his wonderful Win32 Assembly article series. However, by doing so, we have less control: we cannot put any verification in the loop, like accelerator handling, for example. So, let’s keep the loop in our code.
4.1. Enabling Visual Styles
In order to get the common controls 6 visual styles, introduced with Windows XP, you must not only call InitCommonControls
(declared in CommCtrl.h), but also embed a manifest XML file into your code. Fortunately, there is a handy trick you can use in the Visual C++ compiler, which I learned from Raymond Chen’s blog. Just add this to your code:
#pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"")
This will generate and embed the XML manifest file automatically, and you’ll never worry about it again.
To call InitCommonControls
, you must statically link your program to ComCtl32.lib, and this can be accomplished with a #pragma comment
directive as well:
#pragma comment(lib, "ComCtl32.lib")
4.2. Our WinMain
So far, this is our complete WinMain
function (without the dialog box procedure yet):
#include <Windows.h> #include <CommCtrl.h> #include <tchar.h> #include "resource.h" #pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"") #pragma comment(lib, "ComCtl32.lib") int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow) { HWND hDlg; MSG msg; BOOL ret; InitCommonControls(); hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow); while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; }
5. Dialog Box Procedure
The dialog procedure is responsible for handling all program messages, responding to all events. It starts like this:
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return FALSE;
}
Windows calls this function for every program message. If we return FALSE
, it means Windows can carry out the default processing for the message, because we’re not interested in it; if we return TRUE
, we tell Windows we’ve actually processed the message. This is slightly different from the “raw” window message handling through WndProc
, where you return a call to the DefWindowProc
function. Here, we must not call DefWindowProc
, just return FALSE
.
So, we’ll write only the handling of messages that are interesting to us. Among the most commonly used messages, we have WM_INITDIALOG
, WM_COMMAND
, and WM_SIZE
. But to build a minimal functional program, we need only two:
switch(uMsg) { case WM_CLOSE: return TRUE; case WM_DESTROY: return TRUE; }
Notice we don’t need to handle the WM_PAINT
message with dialog boxes.
5.1. The Minimal Message Handling
WM_CLOSE
is called just prior to window closing. If you want to ask the user if he really wants to close the program, here is the place to put this check. To close the window, we call DestroyWindow
– if we don’t call it, the window won’t be closed.
So here’s the message handling, also prompting the user. If you don’t need to prompt the user, just omit the MessageBox
check and call DestroyWindow
directly. And don’t forget to return TRUE
here, whether you close the window or not:
case WM_CLOSE: if(MessageBox(hDlg, TEXT("Close the window?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } return TRUE;
Finally, we must handle the WM_DESTROY
message, telling Windows we want to quit the main program thread. We do this by calling the PostQuitMessage
function:
case WM_DESTROY: PostQuitMessage(0); return TRUE;
The WM_DESTROY
message is also the best place to free resources that were allocated by the program and are still waiting to be deallocated – it’s final cleanup time. But don’t forget to do the cleanup before calling PostQuitMessage
.
5.2. Closing on ESC
An interesting feature of the dialog boxes is that they can be easily programmed to be closed when the user hits the ESC key, and it can also be done when the dialog box is the main window as well. To do so, we must handle the WM_COMMAND
message and wait for the IDCANCEL
identifier, which comes in the low word of the WPARAM
argument, and that’s what we do:
case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: SendMessage(hDlg, WM_CLOSE, 0, 0); return TRUE; } break;
The IDCANCEL
identifier is declared in WinUser.h, which is included in Windows.h, so it’s always available.
Notice that when handling IDCANCEL
, we send a WM_CLOSE
message to our dialog window, which causes the dialog procedure to be called again with the WM_CLOSE
message that we previously coded, so the user will be prompted if he wants to close the window (because that’s the way we coded it).
6. The Final Program
So here is our final program. It’s the C source code for a minimally functional Win32 dialog based program, with the message loop and visual styles properly enabled, just ready to go. You can keep this to use as the skeleton for any Win32 dialog based program.
#include <Windows.h> #include <CommCtrl.h> #include <tchar.h> #include "resource.h" #pragma comment(linker, ""/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'"") #pragma comment(lib, "ComCtl32.lib") INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: SendMessage(hDlg, WM_CLOSE, 0, 0); return TRUE; } break; case WM_CLOSE: if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } return TRUE; case WM_DESTROY: PostQuitMessage(0); return TRUE; } return FALSE; } int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow) { HWND hDlg; MSG msg; BOOL ret; InitCommonControls(); hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); ShowWindow(hDlg, nCmdShow); while((ret = GetMessage(&msg, 0, 0, 0)) != 0) { if(ret == -1) return -1; if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; }
7. Further Organization
Usually, when your program grows in complexity, you’ll end up with a huge DialogProc
stuffed with code, and therefore very painful to maintain. A useful approach to this is the use of function calls to each message — the famous subroutines. It’s specially handy because it isolates the logic of the code, you can see clearly each part of the program, giving you the notion of responding to events. For example, our program could have two dedicated functions:
void onCancel(HWND hDlg) { SendMessage(hDlg, WM_CLOSE, 0, 0); } void onClose(HWND hDlg) { if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES) { DestroyWindow(hDlg); } }
And it would allow us to rewrite our DialogProc
like this:
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: onCancel(hDlg); return TRUE; } break; case WM_CLOSE: onClose(hDlg); return TRUE; case WM_DESTROY: PostQuitMessage(0); return TRUE; } return FALSE; }
History
- 20th July, 2011: Initial version
This article, along with any associated source code and files, is licensed under A Public Domain dedication
This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.
Written on 13 Февраля 2007. Posted in Win32
В Microsoft Windows, диалоговое окно (dialog box) — временное окно, которое создает прикладная программа, чтобы получить данные, вводимые пользователем. Прикладная программа обычно использует диалоговые окна, чтобы запросить пользователя о дополнительной информации для команд. Диалоговое окно обычно содержит один или большее количество элементов управления (дочерние окна), с помощью которых пользователь вводит текст, выбирает параметры, или управляет действием команды.
О диалоговых окнах
Windows предоставляет множество функций, сообщений и предопределенных элементов управления, которые помогают создавать и управлять диалоговыми окнами, таким образом облегчая процесс разработки интерфейса пользователя для прикладной программы. Этот краткий обзор описывает функции и сообщения диалогового окна и объясняет, как использовать их, чтобы создавать и использовать блоки диалога.
Windows предоставляет также много предопределенных, или «стандартных» диалоговых окон, которые поддерживают команды, типа Открыть файл (File Open)и Печатать файл (File Print). Прикладные программы, которые используют эти команды, должны использовать эти стандартные диалоговые окна, чтобы запрашивать от пользователя ввода тех же самых данных, независимо от типа прикладной программы, команды которой исполняются. Для получения дополнительной информации о использовании стандартных блоков диалога в ваших прикладных программах, см. главу Библиотека стандартных диалоговых окон.
Когда используется диалоговое окно
Большинство прикладных программ использует диалоговые окна, чтобы запросить дополнительную информацию для команд, которые требуют ввода данных от пользователя. Использование диалогового окна — единственное рекомендованное средство для прикладной программы, чтобы получить ввод данных. Например, команда Открыть файл (File Open) требует для открытия название файла, так что прикладная программа должна использовать блок диалога, чтобы запросить у пользователя его имя. В таких случаях, прикладная программа создает диалоговое окно, где пользователь выбирает команду и немедленно уничтожает его окно после того, как пользователь дает информацию.
Многие прикладные программы также используют диалоговые окна, чтобы отобразить информацию или параметры, в то время как пользователь работает в другом окне. Например, прикладные программы обработки текстов часто используют диалоговое окно с командой поиска фрагмента текста. До тех пор, пока прикладная программа ищет текст, диалоговое окно остается на экране. Пользователь может затем возвратиться в блок диалога и искать то же самое слово снова; или может изменить введенное в диалоговом окне и искать новое слово. Прикладные программы, которые используют блоки диалога таким образом, обычно создают его тогда, когда пользователь выбирает команду и продолжают показывать его до тех пор, пока прикладная программа выполняется или пока пользователь явно не закроет диалоговое окно.
Чтобы поддерживать использование диалоговых окон различными прикладными программами, Windows предоставляет два типа блока диалога: модальное и немодальное. Модальное диалоговое окно (modal dialog box) требует, чтобы пользователь предоставил информацию или отменил диалоговое окно перед разрешением продолжения работы прикладной программе. Приложения используют модальные блоки диалога вместе с командами, которые требуют дополнительной информации прежде, чем они могут продолжать действовать. Немодальное диалоговое окно (modeless dialog box) позволяет пользователю предоставлять информацию и возвращаться к предыдущей задаче без закрытия блока диалога. Модальные диалоговые окна более простые для управления, чем немодальные блоки диалога, потому что они создаются, исполняют свою задачу и разрушаются вызовом единственной функции.
Чтобы создать или модальное или немодальное диалоговое окно, прикладная программа должна снабдить блок диалога шаблоном, чтобы описать стиль и содержание диалогового окна; приложение должно также снабдить блок диалога процедурой, чтобы выполнять задачи. Шаблон диалогового окна (dialog box template) — бинарное описание блока диалога и элементов управления, которое оно содержит. Разработчик может создать этот шаблон как ресурс, который будет загружен из исполняемого файла прикладной программы, или создать его в памяти, пока выполняется прикладная программа. Процедура диалогового окна (dialog box procedure) — определяемая программой функция повторного вызова, которую Windows вызывает, когда операционная система получает ввод данных для диалогового окна или задачу для выполнения в блоке диалога. Хотя процедура диалогового окна подобна оконной процедуре, у неё не те же самые обязанности.
Прикладная программа обычно создает диалоговое окно, используя либо функцию DialogBox, либо CreateDialog. Функция DialogBox создает модальное диалоговое окно; CreateDialog создает немодальный блок диалога. Эти две функции загружают шаблон блока диалога из исполняемого файла приложения и создают выскакивающее окно, которое соответствует технической спецификации шаблона. Имеются другие функции, которые создают диалоговое окно, используя шаблоны в памяти; они передают дополнительную информацию в процедуру диалогового окна, так как блок диалога создан.
Диалоговые окна обычно принадлежат предопределенному, исключительному классу окна. Windows использует этот класс окна и его соответствующую оконную процедуру и для модальных, и для немодальных диалоговых окон. Когда функция вызывается, она создает окно для блока диалога, такие же как окна для элементов управления в диалоговом окне, затем посылает выбранные сообщения процедуре блока диалога. Пока диалоговое окно видимое, предопределенная оконная процедура управляет всеми сообщениями, обрабатывая некоторые сообщения и пропуская другие в процедуру блока диалога так, чтобы процедура могла выполнять задачи. Прикладные программы не имеют прямого доступа к предопределенному классу окна или оконной процедуре, но они могут использовать шаблон блока диалога и процедуру диалогового окна, чтобы изменить его стиль и поведение.
Окно владелец
Большинство диалоговых окон имеет окно владельца (или чаще просто, владелец). При создании блока диалога, прикладная программа устанавливает владельца, при помощи определения дескриптора окна владельца. Windows использует владельца, чтобы регулировать позицию диалогового окна в Z-последовательности так, чтобы блок диалога всегда устанавливался выше своего владельца. Windows также может посылать сообщения оконной процедуре владельца, уведомляя его о событиях в диалоговом окне.
Windows автоматически скрывает или уничтожает диалоговое окно всякий раз, когда его владелец скрывается или разрушается. Это означает, что процедура диалогового окна не требует какой-либо специальной обработки, чтобы обнаружить изменения в состоянии окна владельца.
Поскольку типичное диалоговое окно используется совместно с командами в меню, окно владельца является обычным окном, содержащим меню. Конечно, можно создать блок диалога, которое не имеет никакого владельца, но это не рекомендуется. Например, когда модальное диалоговое окно не имеет владельца, Windows не отключает какие-либо другие окна прикладной программы и позволяет пользователю продолжать выполнять работу в них, разрушая цели модального блока диалога.
Когда у немодального диалогового окна нет владельца, Windows ни скрывает, ни уничтожает блок диалога, когда другие окна в прикладной программе скрываются или разрушаются. Хотя это и не наносит ущерба цели немодального диалогового окна, однако, требуется, чтобы приложение выполнило специальную обработку, которое гарантирует, что диалоговое окно в нужный момент времени будет скрыто и разрушено.
Окна сообщений
Окно сообщения (message box) — специальное диалоговое окно, которое прикладная программа может использовать, чтобы показывать сообщения и приглашение для обычного ввода данных. Окно сообщения обычно содержит текстовое сообщение и одну или большее количество кнопок. Прикладная программа создает окно сообщения, используя функцию MessageBox или MessageBoxEx, определяя текст, число и типы кнопок для показа. Функция MessageBoxEx позволяет Вам также установить язык, который надо использовать для текста любых предопределенных командных кнопок в окне сообщения.
Хотя окно сообщения является диалоговым окном, Windows берет полностью на себя управление созданием и руководство окном сообщения. Это означает, что прикладная программа не предоставляет шаблон и процедуру диалогового окна. Windows создает свой собственный шаблон, основанный на тексте и кнопках, заданных для окна сообщения и предоставляет свою собственную процедуру диалогового окна.
Окно сообщения — модальное диалоговое окно и Windows создает его, используя те же самые внутренние функции, что и DialogBox. Если прикладная программа определяет окно владельца при вызове функции MessageBox или MessageBoxEx, Windows отключает владельца. Когда диалоговое окно создается, при помощи определения значение MB_TASKMODAL, приложение может также дать указание Windows, чтобы отключить все окна верхнего уровня, принадлежащие к текущей задаче.
Windows может посылать владельцу сообщения типа WM_CANCELMODE и WM_ENABLE также, как она это делает при создании модального диалогового окна. Окно владельца должно завершить любые действия, требующиеся в соответствии с этими сообщениями.
Модальные диалоговые окна
Модальное диалоговое окно должно быть выскакивающим окном, имеющим Системное меню, строку заголовка, и жирную рамку; то есть, шаблон блока диалога должен установить стили WS_POPUP, WS_SYSMENU, WS_CAPTION и DS_MODALFRAME. Хотя прикладная программа может определять и стиль WS_VISIBLE, Windows всегда показывает модальное диалоговое окно независимо от того, устанавливает ли шаблон диалогового окна стиль WS_VISIBLE. Приложение не должно создавать модальное диалоговое окно, имеющее стиль WS_CHILD. Модальный блок диалога с этим стилем отключает сам себя, не допуская какого-либо последующего ввода данных из связанной с ним прикладной программы.
Прикладная программа создает модальное диалоговое окно, используя или функцию DialogBox или DialogBoxIndirect. DialogBox требует названия или идентификатора ресурса, содержащего шаблон блока диалога; DialogBoxIndirect требует дескриптора объекта памяти, содержащего шаблон диалогового окна. Функции DialogBoxParam и DialogBoxIndirectParam также создают модальные блоки диалога; они идентичны выше упомянутым функциям, но, когда диалоговое окно создается, передают заданный параметр для процедуры блока диалога.
При создании модального диалогового окна, Windows делает его активным окном. Диалоговое окно остается активным до тех пор, пока процедура блока диалога не вызовет функцию EndDialog, или пока Windows не активизирует окно в другой прикладной программе. Ни пользователь, ни прикладная программа не могут сделать окно владельца активным, пока модальное диалоговое окно не разрушено.
Когда окно владельца ещё не заблокировано, Windows, создавая модальное диалоговое окно, автоматически отключает окно и любые дочерние окна, принадлежащие ему. Окно владельца остается заблокированным до тех пор, пока блок диалога не будет разрушен. Хотя процедура диалогового окна может потенциально включить окно владельца в любое время, включение владельца уничтожает цели модального диалогового окна и не рекомендуется. Когда процедура блока диалога разрушена, Windows включает окно владельца снова, но только тогда, если модальное диалоговое окно заставило владельца быть отключенным.
Как только Windows создаст модальное диалоговое окно, она посылает сообщение WM_CANCELMODE окну (если оно есть), которое в настоящее время захватило ввод данных от мыши. Прикладная программа, которая принимает это сообщение, должна освободить захваченную мышь так, чтобы пользователь мог переместить мышь в модальное диалоговое окно. Поскольку Windows отключает окно владельца, весь ввод данных от мыши будет потерян, если владелец не выполняет требование освободить мышь после приема этого сообщения.
Чтобы обрабатывать сообщения для модального диалогового окна, Windows запускает его собственный цикл сообщений, принимая временное управление очередью сообщений для всей прикладной программы. Когда Windows извлекает сообщение, которое явно не для блока диалога, она (ОС) посылает сообщение соответствующему окну. Если оперативная система извлекает сообщение WM_QUIT, то она передает сообщение назад в очередь сообщения прикладной программы так, чтобы главный цикл сообщений прикладной программы мог, в конечном счете, отыскать это сообщение.
Примечание: здесь и далее ОС – оперативная система.
Windows передает сообщение WM_ENTERIDLE владельцу окна всякий раз, когда пустеет очередь сообщений прикладной программы. Приложение может использовать это сообщение, чтобы выполнить фоновую задачу, пока диалоговое окно остается на экране. Когда прикладная программа использует это сообщение таким способом, она должна часто уступать управление (например, когда используется функция PeekMessage) таким образом, чтобы модальное диалоговое окно могло принять любой ввод данных от пользователя. Чтобы не допустить передачу модальным диалоговым окном сообщения WM_ENTERIDLE, прикладная программа, когда создается диалоговое окно, может определить стиль DS_NOIDLEMSG.
Прикладная программа разрушает модальное диалоговое окно, используя функцию EndDialog. В большинстве случаев, процедура диалогового окна вызывает EndDialog тогда, когда пользователь выбирает из системного меню блака диалога команду Закрыть (Close), или выбирает в диалоговом окне кнопку ОК или Отменить (Cancel). Блок диалога может возвратить значение через функцию DialogBox (или другие создающие функции), определяя значение при вызове функции EndDialog. Windows возвращает это значение после разрушения диалогового окна. Большинство прикладных программ использует это возвращаемое значение, чтобы определить, успешно ли завершил блок диалога свою задачу или она была отменена пользователем. Windows не возвращает управление из функции, которая создает блок диалога до тех пор, пока процедура диалогового окна не вызовет функцию EndDialog.
Немодальные диалоговые окна
Немодальные диалоговые окна должны быть выскакивающими окнами, у которых есть Системное меню, строка заголовка и тонкая рамка; то есть, шаблон блока диалога должен установить стили WS_POPUP, WS_CAPTION, WS_BORDER и WS_SYSMENU. Windows автоматически не показывает диалоговое окно, если в шаблоне не установлен стиль WS_VISIBLE.
Прикладная программа создает немодальное диалоговое окно, используя функции или CreateDialog, или CreateDialogIndirect. CreateDialog требует названия или идентификатора ресурса, содержащего шаблон блока диалога; CreateDialogIndirect требует дескриптора объекта памяти, содержащего шаблон диалогового окна. Две другие функции, CreateDialogParam и CreateDialogIndirectParam, тоже создают немодальное диалоговое окно; функции, когда окно создается, посылают заданный параметр в процедуру блока диалога.
CreateDialog и другие создающие функции возвращают значение дескриптора родительского окна диалоговому окну. Прикладная программа и процедура блока диалога могут использовать этот дескриптор для управления диалоговым окном. Например, если в шаблоне блока диалога не определен стиль WS_VISIBLE, то приложение может показать диалоговое окно путем передачи дескриптора родительского окна в функцию ShowWindow.
Немодальное диалоговое окно не блокирует окно владельца, не передает какие-либо сообщения для него. Когда создается блок диалога, Windows делает его активным окном, однако пользователь или прикладная программа могут в любое время заменить активное окно. Если диалоговое окно становиться неактивным, оно остается в Z-последовательности выше окна владельца, даже если окно владелец активное.
Прикладная программа ответственна за извлечение и распределение входящих сообщений для диалогового окна. Большинство приложений используют для этого главный цикл сообщений. Чтобы дать возможность пользователю перемещаться и выбирать элементы управления, используя клавиатуру, как угодно, но прикладная программа должна вызвать функцию IsDialogMessage. Более подробную информацию об этой функции, смотри статье Интерфейс клавиатуры диалогового окна.
Немодальное диалоговое окно не может возвратить значение в прикладную программу, как это делает модальное диалоговое окно, однако процедура блока диалога может передать информацию в окно владельца, используя функцию SendMessage.
Прикладная программа перед завершением работы должна разрушить все немодальные диалоговые окна. Она может разрушить немодальный блок диалога, используя функцию DestroyWindow. В большинстве случаев, процедура диалогового окна вызывает DestroyWindow в ответ на ввод пользователем данных, например таких как выбор кнопки Отменить (Cancel). Если пользователь не закрывает диалоговое окно таким способом, тогда прикладная программа должна вызвать DestroyWindow.
DestroyWindow аннулирует дескриптор родительского окна для диалогового окна, так что любой более поздний вызов функции, которая использует этот дескриптор, возвратит значение ошибки. Чтобы не допустить ошибки, процедура диалогового окна должна оповестить владельца, что блок диалога был разрушен. Многие прикладные программы сохраняют глобальную переменную, которая содержит дескриптор для диалогового окна. Когда процедура блока диалога разрушает диалоговое окно, она также и глобальную переменную устанавливает в значение ПУСТО (NULL), показывая, что диалоговое окно больше не действует.
Процедура блока диалога не должна вызывать функцию EndDialog, чтобы разрушить не модальное диалоговое окно.
Шаблон диалогового окна
Шаблон диалогового окна (dialog box template) — двоичные данные, которые описываю блок диалога, определяя высоту, ширину, стиль и содержащиеся в нем элементы управления. Чтобы создать диалоговое окно, Windows или загружает шаблон блока диалога из ресурса исполняемого файла приложения или использует шаблон, передав его в глобальную память прикладной программы. И в том и в другом случае, прикладная программа должна получить шаблон, когда создается диалоговое окно.
Разработчик, создавая ресурсы шаблонов, использует компилятор ресурсов или редактор диалогового окна. Компилятор ресурсов преобразует текстовое описание в ресурс в двоичном коде, а редактор диалогового окна сохраняет в интерактивном режиме диалоговое окно, как ресурс в двоичном коде.
Примечание: Объяснение, как создать ресурс шаблона и добавить его в исполняемый файл прикладной программы, за пределами зоны внимания этого краткого обзора. За большей информацией о создании ресурсов шаблонов и дополнение ими исполняемого файла, обратитесь к документации, предоставленной вам вместе с инструментами разработки программ.
Чтобы создать диалоговое окно без использования ресурсов шаблонов, вы должны создать шаблон в в памяти и переслать его в функцию CreateDialogIndirectParam или DialogBoxIndirectParam или в макрокоманду CreateDialogIndirect или DialogBoxIndirect.
Шаблон диалогового окна в памяти состоит из заголовка, который описывает блок диалога, сопровождаемого одним или большим количеством дополнительных блоков данных, которые описывают каждый элемент управления в диалоговом окне. Шаблон может использовать или стандартный или расширенный формат. В стандартном шаблоне заголовок — структура DLGTEMPLATE, сопровождаемая дополнительными массивами переменной длины; а данные для каждого элемента управления состоят из структуры DLGITEMTEMPLATE, сопровождаемой дополнительными массивами переменной длины. В шаблоне расширенного диалогового окна, заголовок использует формат DLGTEMPLATEEX, а для определений элементов управлений используется формат DLGITEMTEMPLATEEX.
Вы можете создать шаблон в памяти, размещая его в глобальной памяти и заполняя его стандартным или расширенным заголовком и определениями элементов управления. Шаблон в памяти по форме и содержанию аналогичен шаблону ресурса. Многие прикладные программы, которые используют шаблоны в памяти, сначала использую функцию LoadResource, чтобы загрузить ресурс шаблона в память, а затем модифицируют загруженный ресурс, чтобы создать новый шаблон в памяти. За большей информацией о создании шаблона диалогового окна в памяти, обратись к статье Шаблоны в памяти.
Следующие разделы описывают стили, размеры и другие значения, используемые в шаблоне диалогового окна.
Стили шаблона диалогового окна
Каждый шаблон диалогового окна определяет комбинацию стилей, значения которых задают внешний вид и свойства блока диалога. Значениями стиля могут быть стили окна, такие как WS_POPUP и WS_SYSMENU и стили диалогового окна, такие как DS_MODALFRAME. Число и типы стилей зависят от типа и предназначения блока диалога.
Когда создается диалоговое окно, Windows передает все стили окна, полученные из шаблона, в функцию CreateWindowEx. Windows может передать один или большее количество стилей, которые зависимы от стилей, данных в диалоговом окне. Например, когда, при создании блока диалога, шаблон определяет стиль DS_MODALFRAME, Windows использует WS_EX_DLGMODALFRAME. Когда шаблон устанавливает стиль DS_SYSMODAL, Windows использует WS_EX_TOPMOST. Все другие стили блока диалога находятся под влиянием того, как Windows управляет диалоговым окном.
Большинство диалоговых окон, выскакивающие окна, в которых есть системное меню и строка заголовка. Поэтому, в обычном шаблоне определяют стили WS_POPUP, WS_SYSMENU и WS_CAPTION. Шаблон также определяет стиль рамки: WS_BORDER для не модальных диалоговых окон и DS_MODALFRAME для модальных блоков диалога. Шаблон может определить тип окна, отличающийся от выскакивающего (например, такой как WS_OVERLAPPED), если он создает пользовательское окно взамен диалогового окна.
Windows всегда показывает модальное диалоговое окно, независимо от того, дан или нет стиль WS_VISIBLE; Windows автоматически показывает блок диалога, когда он создан. В противном случае, прикладная программа дублирует показ диалогового окна, используя функцию ShowWindow.
Шаблон может определить стиль DS_SETFOREGROUND, чтобы заставить Windows перевести диалоговое окно в разряд приоритетных окон. Это особенно полезно для модальных блоков диалога, которые требуют незамедлительного внимания к себе от пользователя, не принимая во внимание, какое окно владелец или нет — приоритетное окно.
Когда используется стиль DS_ABSALIGN, Windows трактует размеры диалогового окна, как экранные координаты; при использовании стиля DS_SETFONT, Windows, вместо системного шрифта, использует установленный шрифт, чтобы прописывать текст в рабочей области и в элементах управления диалогового окна; стильDS_NOIDLEMSG препятствует модальному блоку диалога передавать сообщения WM_ENTERIDLE в окно владельца. Эти стили описаны более детально в разделах и статьях ниже.
Стиль DS_LOCALEDIT для прикладных программ, базирующихся на Win32, не применяется.
Диалоговые окна со стилем DS_SYSMODAL, принимают стиль окна WS_EX_TOPMOST, но никаких других специальных свойств или стилей; это означает, что пользователь все еще имеет доступ к другим окнам на рабочем столе даже притом, что блок диалога DS_SYSMODAL может быть показано.
Размеры диалогового окна
Шаблон каждого диалогового окна содержит размеры, которые устанавливают позицию, ширину и высоту блока диалога и элементов управления, которые содержит он. Это аппаратно-независимые размеры, так что прикладная программа может использовать единственный шаблон для создания одного и того же диалогового окна для всех типов устройств изображения. Это гарантирует то, что блок диалога будет иметь те же самые пропорции и внешний вид на всех экранах, несмотря на различное разрешение и отношение сторон между экранами.
Размеры диалогового окна устанавливаются в базовых единицах диалога. Одна единица по горизонтали эквивалентна одной четверти средней ширины символа системного шрифта. Одна единица по вертикали эквивалентна одной восьмой средней высоты символа системного шрифта. Прикладная программа может извлечь информацию о числе пикселей на базовую единицу измерения для текущего изображения при помощи функции GetDialogBaseUnits. Приложение может преобразовать размеры из базовых единиц диалогового окна в пиксели, используя функцию MapDialogRect.
Шаблон должен устанавливать начальные координаты верхнего левого угла диалогового окна. Обычно, это координаты относительно верхнего левого угла рабочей области окна владельца. Когда шаблон устанавливает стиль DS_ABSALIGN или у диалогового окна нет владельца, позиция определяется относительно верхнего левого угла экрана. Windows устанавливает эту первоначальную позицию, когда создает диалоговое окно, но дает возможность прикладной программе регулировать позицию блока диалога перед его показом. Например, приложение может извлечь габариты окна владельца, вычислить новую позицию, в которую помещает диалоговое окно в окне владельца, а затем установить позицию, используя функцию SetWindowPos.
Шаблон должен установить ширину и высоту диалогового окна, которые не должны быть больше ширины и высоты экрана, и гарантировать, что все элементы управления находятся внутри рабочей области блока диалога. Хотя Windows и дает возможность диалоговому окну быть любого размера, но создавая его слишком маленьким или слишком большим можно этим воспрепятствовать пользователю ввести предусмотренные данные, расстраивая цели блока диалога. Многие прикладные программы используют больше чем одно диалоговое окно, когда имеется большое количество элементов управления. В таких случаях, начальный блок диалога обычно содержит одну или большее количество кнопок, которые пользователь может выбирать, чтобы показать на экране следующее диалоговое окно.
Элементы управления диалогового окна
Шаблон устанавливает позицию, ширину, высоту, стиль, идентификаторы и класс окна для каждого элемента управления в диалоговом окне. Windows создает каждый элемент управления путем передачи их данных в функцию CreateWindowEx. Элементы управления создаются по порядку, в котором они установлены в шаблоне. Шаблон должен определить соответствующее число, тип и порядок элементов управления, чтобы гарантировать, что пользователь может сделать ввод необходимых данных, чтобы завершить команду, связанную с диалоговым окном.
Для каждого элемента управления шаблон устанавливает значения стиля, которые определяют внешний вид и действие элемента управления. Каждый элемент управления — это дочернее окно, и поэтому должно иметь стиль WS_CHILD. Чтобы гарантировать, что элемент управления видимый, когда отображается диалоговое окно, каждый элемент управления должен иметь также стиль WS_VISIBLE. Другие, обычно используемые стили окна, — это WS_BORDER для элементов управления, которые не обязательно имеют рамки, WS_DISABLED для элементов управления, которые должны быть отключены, когда создается первоначальное диалоговое окно и WS_TABSTOP и WS_GROUP для элементов управления, к которым можно обращаться, используя клавиатуру. Стили WS_TABSTOP и WS_GROUP используются совместно с диалоговым интерфейсом клавиатуры, описанном позже в этом разделе.
Шаблон может также установить стили элементов управления, специфические для класса элементов управления окна. Например, шаблон, который определяет кнопку управления, должен дать кнопке управления стиль, такой как BS_PUSHBUTTON или BS_CHECKBOX. Windows передает стиль элемента управления в управляющую окном процедуру через посредство сообщения WM_CREATE, разрешая процедуре приспосабливать внешний вид и работу элемента управления.
Windows преобразует значения позиции координат, ширину и высоту из базовых единиц диалога в пиксели, перед передачей их в CreateWindowEx. Когда Windows создает элемент управления, он определяет диалоговое окно как родительское окно. Это означает, что Windows всегда воспринимает координаты расположения элемента управления как рабочие координаты, относительно верхнего левого угла рабочей области блока диалога.
Шаблон определяет класс окна для каждого элемента управления. Обычно диалоговое окно содержит элементы управления, принадлежащие предопределенным элементам управления класса окна, такие как кнопка и поле редактирования класса окна. В этом случае, шаблон определяет класс окна путем присваивания соответствующего предопределенного значения атому класса. Когда диалоговое окно содержит элемент управления, принадлежащий классу пользовательских элементов управления окна, шаблон дает название этого зарегистрированного класса окна или значение атома, в настоящее время связанного с этим названием.
Каждый элемент управления в диалоговом окне должен иметь уникальный идентификатор для отличия его от других элементов управления. Элементы управления передают информацию процедуре блока диалога посредством сообщения WM_COMMAND, так что идентификаторы элементов управления необходимы для процедуры, чтобы различать, какой элемент управления передал данное сообщение. Единственным исключением из этого правила являются идентификаторы статических элементов управления. Статические элементы управления не требуют уникального идентификатора, так как они не предают сообщения WM_COMMAND.
Чтобы разрешить пользователю закрыть диалоговое окно, шаблон должен установить, по крайней мере, одну командную кнопку и присвоить ей идентификатор управления IDCANCEL. Чтобы разрешить пользователю выбор между завершающей и отменяющей командами, связанными с диалоговым окном, шаблон должен установить две командные кнопки с надписями ОК и Отменить (Cancel) и управляющими идентификаторами IDOK и IDCANCEL, соответственно.
Шаблон устанавливает также необязательный текст и данные для создания элемента управления. Текст обычно предназначен для обозначения кнопок управления или установки начального содержания статического текстового элемента управления. Данные создания — это один или большее количество байтов данных, которые Windows передает оконной процедуре элемента управления, когда элемент управления создается. Данные создания полезны для элемента управления, который требует дополнительной информации о своем начальном содержании или стиле, чем это дается другими данными. Например, прикладная программа может использовать данные создания, чтобы установить начальные параметры и диапазон управления полосой прокрутки.
Системное меню
Windows снабжает диалоговое окно Системным меню, в том случае, если шаблон определяет стиль WS_SYSMENU. Чтобы не допустить ввода несоответствующей команды, Windows автоматически блокирует работу всех команд в меню, исключая команды Переместить (Move) и Закрыть (Close). Пользователь может использовать команду Переместить (Move) для перемещения диалогового окна. Если пользователь выбирает команду Закрыть (Close), Windows в процедуру диалогового окна передает сообщение WM_COMMAND с параметром wParam, установленным в IDCANCEL. Это то же самое сообщение, которое посылается кнопкой Отменить (Cancel), когда пользователь выбирает её. Рекомендуемым действием для этого сообщения является закрыть окно диалога и отменить запрошенную команду или задачу.
Не смотря на то, что другие меню в диалоговых окнах не рекомендуются, шаблон блока диалога может установить меню при помощи предоставленного идентификатора или названия ресурса меню. В этом случае, Windows загружает ресурс и создает меню для диалогового окна. Прикладные программы обычно используют идентификаторы меню или названия в шаблонах, когда шаблоны используются для создания пользовательских, а не диалоговых окон.
Диалоговое окно Шрифты (Fonts)
Все тексты диалогового окна Windows пишет, используя по умолчанию системный шрифт. При помощи стиля DS_SETFONT прикладная программа может предписать Windows использовать в диалоговом окне другой шрифт и установить размер в пунктах и название шрифта. Не смотря на то, что шаблон диалогового окна может установить шрифт, Windows для заголовков и меню блока диалога всегда использует системный шрифт; стиль DS_SETFONT этого не меняет.
Когда установлен стиль DS_SETFONT, система передает процедуре диалогового окна и каждому элементу управления, когда она создает элементы управления, сообщение WM_SETFONT. Процедура диалогового окна ответственна за сохранение дескриптора шрифта при передаче сообщения DS_SETFONT и выбор дескриптора в контексте устройства отображения всегда, когда она записывает текст в окне. Предопределенные элементы управления делают это по умолчанию.
Когда дается стиль DS_SETFONT, Windows использует среднюю символьную ширину шрифта, чтобы вычислить позицию и габариты диалогового окна. Иначе, он использует среднюю символьную ширину системного шрифта.
Шаблоны в памяти
Шаблон диалогового окна в памяти состоит из заголовка, описывающего диалоговое окно, который сопровождается одним или большим числом дополнительных блоков данных, которые описывают каждый из элементов управления в блоке диалога. Шаблон может использовать или стандартный или расширенный формат. В стандартном шаблоне, заголовочный файл – это структура DLGTEMPLATE, сопровождаемая дополнительными массивами переменной длины. Данные для каждого элемента управления состоят из структуры DLGITEMTEMPLATE, сопровождаемой дополнительными массивами переменной длины. В расширенном шаблоне диалогового окна, заголовочный файл использует формат DLGTEMPLATEEX и определения элементов управления, использующие формат DLGITEMTEMPLATEEX.
Чтобы отличить стандартный шаблон от расширенного, проверьте первые 16 битов шаблона диалогового окна. В расширенном шаблоне первое слово(WORD). – 0хFFFF; любое другое значение показывает, что это стандартный шаблон.
Если вы создаете шаблон блока диалога в памяти, вы должны гарантировать, что каждый элемент управления DLGITEMTEMPLATE или DLGITEMTEMPLATEEX выровнен по границе ДВОЙНОГО СЛОВА (DWORD). Кроме того, любые данные создания, которые следует за определением элемента управления, должны быть выровнены по границе ДВОЙНОГО СЛОВА (DWORD). Все другие массивы переменной длины в шаблоне диалогового окна должны быть выровнены по границам СЛОВА (WORD).
Заголовок шаблона.
В обоих шаблонах диалогового окна, стандартном и расширенном, заголовок включает в себя следующую общую информацию:
- Размещение и габариты диалогового окна.
- Стили окна и блока диалога для диалогового окна.
- Число элементов управления диалогового окна. Это значение обуславливается числом элементов управления DLGITEMTEMPLATE или DLGITEMTEMPLATEEX, которые определены в шаблоне.
- Необязательный ресурс меню для диалогового окна. Шаблон может указывать, что блок диалога не имеет меню, или он может установить значения по порядку, или строку Unicode с нуль-терминатором в конце, которые идентифицируют ресурс меню в исполняемом файле.
- Класс окна диалогового окна. Это может быть или предопределенный класс диалогового окна, или значения по порядку, или строка Unicode с нуль-терминатором в конце, которые идентифицируют зарегистрированный класс окна.
- Строка Unicode с нуль-терминатором в конце, которая определяет заголовок окна блока диалога. Если строка пустая, то поле заголовка диалогового окна не заполняется. Если в блоке диалога не определен стиль WS_CAPTION, система устанавливает заголовок, определенный в строке, но не показывает его.
- Если диалоговое окно имеет стиль DS_SETFONT, заголовок устанавливает размер в пунктах и название шрифта, который используется для текста в рабочей области и элементах управления блока диалога.
В расширенном шаблоне заголовок DLGTEMPLATEEX определяет к тому же следующую дополнительную информацию:
- Идентификатор контекста справки, который идентифицирует окно блока диалога, когда система посылает сообщение WM_HELP.
- Если в диалоговом окне определен стиль DS_SETFONT, заголовок устанавливает толщину шрифта и является ли шрифт курсивным (italic).
Определения элементов управления
Нижеследующий шаблон заголовка – это один или большее количество определений элементов управления, которые описывают элементы управления диалогового окна. И в стандартном и расширенном шаблоне, заголовок блока диалога имеет элемент, который указывает число элементов управления, определяемых в шаблоне. В стандартном шаблоне, каждое определение элемента управления, состоит из структуры DLGITEMTEMPLATE, сопровождаемой дополнительными массивами переменной длины. В расширенном шаблоне, определения элемента управления используют формат DLGITEMTEMPLATEEX.
И в стандартном, и в расширенном шаблонах, определение элемента управления включает в себя следующую информацию:
- Размещение и габариты элемента управления.
- Стили окна и элемента управления для средств управления.
- Идентификатор элемента управления.
- Класс окна элемента управления. Это может быть или порядковые значения предопределенного класса системы, или строка Unicode с нуль-терминатором на конце, которая определяет имя зарегистрированного класса окна.
- Cтрока Unicode с нуль-терминатором на конце, которая определяет начальный текст элемента управления, или перечисление значений, которые идентифицируют ресурс, типа пиктограммы, в исполняемом файле.
- Необязательный переменной длины блок данных создания. Когда система создает элемент управления, она передает указатель на эти данные в параметре lParam сообщения WM_CREATE, которое передается в элемент управления.
В расширенном шаблоне, определение элемента управления также определяет идентификатор справочного контекста, который идентифицирует элемент управления, когда система посылает сообщение WM_HELP.
Процедура диалогового окна
Процедура диалогового окна подобна оконной процедуре, в которую Windows посылает сообщения, чтобы процедура, когда она имеет информацию, задала или завершила задачи. В отличие от оконной процедуры, процедура диалогового окна никогда не вызывает функцию DefWindowProc. Вместо этого, она возвращает Булево значение ИСТИНА (TRUE), если она обрабатывает сообщение или ЛОЖЬ(FALSE), если она этого не делает.
Каждая процедура диалогового окна имеет следующую форму:
BOOL APIENTRY DlgProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message) {// Здесь располагаются case-операторы по обработке сообщений.
default:
return FALSE;
}
}
Параметры процедуры служат тем же самым целям, что и в оконной процедуре, при помощи параметра hwndDlg, принимают дескриптор окна блока диалога.
Большинство процедур диалогового окна обрабатывает сообщение WM_INITDIALOG и сообщения WM_COMMAND, передаваемые элементом управления, но обрабатывает немногие, если имеются какие-либо другие сообщения. Если процедура диалогового окна не обрабатывает сообщение, она должна возвратить значение ЛОЖЬ(FALSE), чтобы заставить Windows обработать сообщения внутри себя. Единственное исключение из этого правила — сообщение WM_INITDIALOG. Процедура диалогового окна должна возвратить значение ИСТИНА (TRUE), чтобы направить в Windows сообщениеWM_INITDIALOG для дальнейшей обработки. В любом случае, процедура не должна вызвать DefWindowProc.
Сообщение WM_INITDIALOG
Windows не передает сообщение WM_CREATE процедуре диалогового окна. Вместо него, она, когда создает диалоговое окно и все его элементы управления, передает сообщение WM_INITDIALOG, но перед этим она показывает диалоговое окно. Процедура должна завершить любой инициализационный запрос, чтобы гарантировать, что блок диалога показывает текущие параметры, связанные с командой или задачей. Например, когда диалоговое окно содержит элемент управления, который показывает текущие диск и каталог, процедура должна установить текущий диск и каталог и установить в элементе управления эти значения.
Процедура может инициализировать элементы управления при помощи использования функций, таких как SetDlgItemText и CheckDlgButton. Поскольку элементы управления тоже окна, процедура может также манипулировать ими при помощи использования функций управления окном, такими как EnableWindow и SetFocus. Процедура может извлечь информацию о дескрипторе окна элемента управления, используя функцию GetDlgItem.
Процедура диалогового окна может изменить, когда это необходимо, содержимое, состояние и расположение любого элемента управления. Например, в диалоговом окне, которое содержит блок со списком имен файлов и кнопку Отрыть (Open), процедура может заблокировать кнопку Открыть, пока пользователь не выберет файл из списка. В этом примере шаблон диалогового окна устанавливает стиль WS_DISABLED для кнопки Открыть и Windows автоматически блокирует кнопку, когда создает ее. Когда процедура диалогового окна принимает уведомительное сообщение от блока со списком, которое указывает, что пользователь выбрал файл, она вызывает функцию EnableWindow, которая разрешает работу кнопки Открыть.
Если прикладная программа создает диалоговое окно при помощи одной из функций DialogBoxParam, DialogBoxIndirectParam, CreateDialogParam или CreateDialogIndirectParam, параметр lParam сообщения WM_INITDIALOG содержит дополнительный параметр, передаваемый в функцию. Прикладные программы обычно и wParam. Если элемент управления не предназначен для принятия по умолчанию фокуса, он может установить фокус в элемент управления, который предназначен для этого, используя функцию SetFocus. Если процедура устанавливает фокус ввода данных, она должна возвратить значение ЛОЖЬ FALSE), чтобы не допустить установку фокуса Windows по умолчанию. По умолчанию, фокус ввода данных получает тот элемент управления, который всегда дается первым в шаблоне, он видимый, его работа не заблокирована и он имеет стиль WS_TABSTOP. Если такого элемента управления не существует, Windows устанавливает по умолчанию фокус ввода данных в первый элемент управления шаблона.
Сообщение WM_COMMAND
Элемент управления может передать в процедуру диалогового окна сообщение WM_COMMAND, когда пользователь завершает деятельность в элементе управления. Эти сообщения, называемые уведомительными сообщениями, информируют процедуру, что пользователь ввел данные и дал разрешение на выполнение присущей ей работы.
Все предопределенные элементы управления, исключая статические элементы управления, передают уведомительные сообщения о действии выбранном пользователем. Например, при нажатии кнопки передается уведомительное сообщение BN_CLICKED всякий раз, когда пользователь выбирает кнопку. Во всех случаях, младшее слово параметра wParam содержит идентификатор элемента управления, старшее слово wParam содержит код уведомления, а параметр lParam содержит дескриптор окна элемента управления.
Процедура диалогового окна должна отслеживать и обрабатывать уведомительные сообщения. В частности, процедура должна обрабатывать сообщения, имеющие идентификаторы IDOK или IDCANCEL; эти сообщения представляют запрос пользователя на закрытие диалогового окна. Процедура должна закрыть блок диалога при помощи функции EndDialog для модального блока диалога и функцию DestroyWindow для не модального диалогового окна.
Windows также передает сообщение WM_COMMAND процедуре диалогового окна, если блок диалога имеет меню, такое как Системное меню, а пользователь выбирает команду. В частности, Windows передает сообщение WM_COMMAND с параметром wParam, установленным в IDCANCEL всякий раз, когда пользователь выбирает в Системном меню диалогового окна команду Закрыть (Close). Сообщение почти идентично уведомительному сообщению, посылаемому кнопкой Cancel и должно быть обработано точно таким же самым способом.
Сообщение WM_PARENTNOTIFY
Элемент управления всегда передает сообщение WM_PARENTNOTIFY, когда пользователь нажимает на клавишу мыши в момент, когда она указывает на элемент управления. Некоторые прикладные программы понимают это сообщение как сигнал к завершению действия, связанного с элементом управления, такого как показ строки текста описывающего предназначение элемента управления.
Windows также передает сообщение WM_PARENTNOTIFY, когда она создает и разрушает окно, но не элементы управления созданные из шаблона диалогового окна. Windows предотвращает эти сообщения, устанавливая стиль WS_EX_NOPARENTNOTIFY при создании элементов управления. Прикладная программа не может отменить это заданное по умолчанию поведение, если она не создает свои собственные элементы управления для диалогового окна.
Сообщения управляющие цветом
Элементы управления и Windows могут передавать сообщения, управляющие цветом тогда, когда они хотят, чтобы процедура диалогового окна нарисовала фон элемента управления или другого окна, при помощи использования заданной кисти и цветов. Это может быть полезно тогда, когда прикладные программы переопределяют использование в диалоговых окнах и в их элементах управления цветов по умолчанию. Ниже перечислены управляющие цветом сообщения, которые заменили сообщение WM_CTLCOLOR.
WM_CTLCOLORBTN
WM_CTLCOLORDLG
WM_CTLCOLOREDIT
WM_CTLCOLORLISTBOX
WM_CTLCOLORMSGBOX
WM_CTLCOLORSCROLLBAR
WM_CTLCOLORSTATIC
Элемент управления передает управляющее цветом сообщение в процедуру диалогового окна непосредственно перед тем, как он начнет рисовать свой собственный фон. Сообщение позволяет процедуре определить, какая используется кисть, и установить цвета фона и переднего плана. Процедура определяет кисть, путем возврата дескриптора кисти. Чтобы установить цвета фона и переднего плана, процедура использует функции SetBkColor и SetTextColor с контекстом устройства управления дисплеем. Управляющее цветом сообщение передает дескриптор контекста устройства дисплея в процедуру в параметре сообщения wParam.
Windows передает сообщение WM_CTLCOLORDLG в процедуру диалогового окна в том случае, если процедура не обрабатывает сообщение WM_ERASEBKGND. У предопределенного класса диалогового окна нет класса кисти фона, таким образом, это сообщение позволяет процедуре определить свой собственный фон без необходимости включать код для завершения работы.
В любом случае, когда процедура диалогового окна не делает обработки управляющего цветом сообщения, Windows использует кисть для цвета окна по умолчанию, чтобы нарисовать фон для всех элементов управления и окон, исключая полосы прокрутки. Прикладная программа может восстановить цвет окна по умолчанию, передав значение COLOR_WINDOW в функцию GetSysColor. В то время пока идет окраска фоном, цвет переднего плана для контекста устройства дисплея устанавливается по умолчанию в цвет текста (COLOR_WINDOWTEXT). Для полос прокрутки, Windows использует кисть, имеющую заданный по умолчанию цвет полосы прокрутки (COLOR_SCROLLBAR). В этом случае, цвета фона и переднего вида для контекста устройства дисплея устанавливаются в белый и черный, соответственно.
Обработка сообщения диалогового окна по умолчанию
Оконная процедура для предопределенного класса диалогового окна выполняет обработку по умолчанию для всех сообщений, которые не обрабатывает процедура блока диалога. Когда процедура диалогового окна возвращает значение ЛОЖЬ(FALSE) для какого-либо сообщения, предопределенная оконная процедура проверяет сообщения и выполняет по умолчанию следующие действия:
- DM_GETDEFID — Вы можете передать это сообщение в диалоговое окно. Блок диалога возвращает идентификатор заданной по умолчанию командной кнопки элемента управления, если таковая имеется; в противном случае он возвращает нуль.
- DM_REPOSITION — Вы можете передать это сообщение в диалоговое окно верхнего уровня. Блок диалога переустанавливается самостоятельно, так как он подгоняет себя в пределах области самого главного окна (рабочего стола программы).
- DM_SETDEFID — Вы можете передать это сообщение диалоговое окно. Блок диалога устанавливает заданную по умолчанию командную кнопку в элементе управления, определенном идентификатором элемента управления в параметре wParam.
- WM_ACTIVATE — Восстанавливает фокус ввода данных в элементе управления, идентифицированном предварительно сохраненным дескриптором, если диалоговое окно активизировано. Иначе, процедура сохраняет дескриптор элемента управления, имеющего фокус ввода данных.
- WM_CHARTOITEM — Возвращает нуль.
- WM_CLOSE — Посылает уведомительное сообщение BN_CLICKED в диалоговое окно, устанавливающее IDCANCEL как идентификатор элемента управления. Если блок диалога имеет идентификатор управления IDCANCEL и элемент управления в настоящее время заблокирован, процедура выдает предупреждение и не передает сообщение.
- WM_COMPAREITEM — Возвращает нуль.
- WM_ERASEBKGND — Заполняет рабочую область диалогового окна, используя или кисть, возвращенную сообщением WM_CTLCOLORDLG или цветом окна, который по умолчанию.
- WM_GETFONT — Возвращает дескриптор определенного программой шрифта диалогового окна.
- WM_INITDIALOG — Возвращает нуль.
- WM_LBUTTONDOWN — Посылает комбинированному блоку, имеющему фокус ввода данных, сообщение CB_SHOWDROPDOWN, предписывая элементу управления скрыть его раскрывающийся список. Процедура вызывает DefWindowProc, чтобы завершить действие по умолчанию.
- WM_NCDESTROY — Освобождает глобальную память, назначенную для средств редактирования в диалоговом окне (применяется в блоках диалога прикладных программах, базирующихся на Windows, в которых установлен стиль DS_LOCALEDIT) и освобождает любой определяемый программой шрифт (применяется в диалоговых окнах, в которых установлен стиль DS_SETFONT). Процедура вызывает функцию DefWindowProc, чтобы завершить действие по умолчанию.
- WM_NCLBUTTONDOWN — Посылает комбинированному блоку, имеющему фокус ввода, сообщение CB_SHOWDROPDOWN предписывая элементу управления скрыть его раскрывающийся список. Процедура вызывает DefWindowProc, чтобы завершить действие по умолчанию.
- WM_NEXTDLGCTL — Устанавливает фокус ввода данных в следующем или предыдущем элементе управления в диалоговом окне, в элементе управления, идентифицированном дескриптором в параметре wParam или в первом элементе управления в диалоговом окне, которое является видимым, не заблокированным и имеет стиль WS_TABSTOP. Процедура игнорирует это сообщение, если текущее окно с фокусом ввода данных — не элемент управления.
- WM_SETFOCUS — Устанавливает фокус ввода данных в элемент управления, идентифицированным предварительно сохраненным дескриптором окна элемента управления. Если такого дескриптора не существует, процедура устанавливает фокус ввода данных в первый элемент управления в шаблоне диалогового окна, который является видимым, не заблокированным и имеет стиль WS_TABSTOP. Если такого элемента управления не существует, процедура устанавливает фокус ввода данных в первый элемент управления в шаблоне.
- WM_SHOWWINDOW — Если диалоговое окно скрыто, сохраняет дескриптор элемента управления, имеющего фокус ввода данных, затем вызывает DefWindowProc, чтобы завершить действие по умолчанию.
- WM_SYSCOMMAND — Если диалоговое окно свернуто, сохраняет дескриптор элемента управления, имеющего фокус ввода данных, затем вызывает DefWindowProc, чтобы завершить действие по умолчанию.
- WM_VKEYTOITEM — Возвращает нуль.
Предопределенная оконная процедура все другие сообщения передает в DefWindowProc для их обработки по умолчанию.
Интерфейс клавиатуры диалогового окна
Windows предоставляет специальный интерфейс клавиатуры для диалоговых окон, который выполняет специальную обработку для некоторых клавиш. Интерфейс создает сообщения, которые соответствуют некоторым кнопкам в блоке диалога или перемещает фокус ввода данных из одного элемента управления в другой. Ниже перечислены клавиши, использующиеся в этом интерфейсе и их соответствующее действие:
- ALT+mnemonic — Перемещает фокус ввода данных в первый элемент управления (имеющий стиль WS_TABSTOP) после статического элемента управления, содержащего данный символ.
- DOWN — Перемещает фокус ввода данных в следующий элемент управления в группе.
- ENTER — Посылает сообщение WM_COMMAND процедуре диалогового окна. В параметре wParam установлен IDOK или идентификатор элемента управления командной кнопки заданной по умолчанию.
- ESC — Посылает сообщение WM_COMMAND процедуре диалогового окна. В параметре wParam установлен флажок IDCANCEL.
- LEFT — Перемещает фокус ввода данных в предыдущий элемент управления в группе.
- mnemonic — Перемещает фокус ввода данных в первый элемент управления (имеющий стиль WS_TABSTOP) после статического элемента управления, содержащего данный символ.
- RIGHT — Перемещает фокус ввода данных в следующий элемент управления в группе.
- SHIFT+TAB — Перемещает фокус ввода в предыдущий элемент управления, который имеет стиль WS_TABSTOP.
- TAB — Перемещает фокус ввода в следующий элемент управления, который имеет стиль WS_TABSTOP.
- UP — Перемещает фокус ввода данных в предыдущий элемент управления в группе.
Win32 API автоматически предоставляет интерфейс клавиатуры для всех модальных диалоговых окон. Она не дает этот интерфейс для немодальных блоков диалога, если прикладная программа не вызвала функцию IsDialogMessage, чтобы фильтровать сообщения в ее главном цикле сообщений. Это означает, что прикладная программа должна передать сообщение в IsDialogMessage немедленно после извлечения сообщения из очереди сообщений. Функция обрабатывает сообщения, если они для диалогового окна и возвращает значение отличное от нуля, чтобы указать, что сообщение было обработано и его невозможно было передать в функции TranslateMessage или DispatchMessage.
Поскольку интерфейс клавиатуры диалогового окна использует клавиши направления, чтобы передвигаться между средством управления в блоке диалога, прикладная программа не может использовать эти клавиши, чтобы листать содержание какого-либо модального диалогового окна или какого-либо немодального блока диалога, для которого вызывается IsDialogMessage. Когда диалоговое окно имеет полосы прокрутки, прикладная программа должна предоставить дополнительный интерфейс клавиатуры для полос прокрутки. Обратите внимание, что интерфейс мыши для прокрутки доступен тогда, когда система включает мышь.
Стиль WS_TABSTOP
Клавиша TAB и сочетание клавиш SHIFT+TAB не действуют, если в элементах управления диалогового окна не определен стиль WS_TABSTOP. Windows разыскивает этот стиль тогда, когда он ищет следующий элемент управления в диалоговом окне, который примет фокус ввода данных.
Когда пользователь нажимает на TAB или SHIFT+TAB, Windows сначала определяет, обрабатывает ли эти клавиши элемент управления, имеющий фокус ввода данных. Он передает элементу управления сообщение WM_GETDLGCODE и, если элемент управления возвращает DLGC_WANTTAB, Windows передает эти клавиши под управление. В противном случае, Windows использует функцию GetNextDlgTabItem, чтобы определить следующий элемент управления, который видимый, не блокирован и у которого определен стиль WS_TABSTOP. Windows начинает поиск элемента управления, в настоящее время имеющего фокус ввода данных, и продолжает по порядку, в котором элементы управления были созданы, то есть по порядку, в котором они определены в шаблоне диалогового окна. Когда система определяет элемент управления с требуемыми характеристиками, Windows перемещает фокус ввода данных в него.
Прикладная программа может также использовать GetNextDlgTabItem, чтобы определить элемент управления, имеющий стиль WS_TABSTOP. Функция извлекает информацию о дескрипторе окна следующего или предыдущего элемента управления, имеющего стиль WS_TABSTOP без перемещения фокуса ввода данных.
Стиль WS_GROUP
По умолчанию Windows перемещает фокус ввода данных в следующий или предыдущий элемент управления всякий раз, когда пользователь нажимает командную кнопку. Если только текущий элемент управления с фокусом ввода данных не обрабатывает эти кнопки, а следующий и предыдущий элементы управления не статические средства управления, Windows продолжает перемещать фокус ввода данных по всем элементам управления, пока пользователь продолжает нажимать командную кнопку.
Прикладная программа может использовать стиль WS_GROUP, чтобы модифицировать это действие по умолчанию. Этот стиль отмечает начало группы элементов управления. Если элемент управления группы имеет фокус ввода данных, когда пользователь начинает нажатие на командные кнопки, фокус остается в группе. В большинстве случаев, первый элемент управления в группе должен иметь стиль WS_GROUP, а все другие элементы управления в группе не должны иметь этого стиля. Все элементы управления в группе должны быть смежными, то есть, они должны быть созданы последовательно, без расположения между ними элементов управления не группы.
Когда пользователь нажимает управляющую кнопку, Windows сначала определяет, обрабатывает ли командные кнопки элемент управления, имеющий в настоящее время фокус ввода. Windows передает сообщение WM_GETDLGCODE и, если элемент управления возвращает значение DLGC_WANTARROWS, передает кнопку под управление. В противном случае, Windows использует функцию GetNextDlgGroupItem, чтобы определить следующий элемент управления в группе.
Функция GetNextDlgGroupItem ищет элементы управления по порядку (или в обратном порядке), как они были созданы. Если пользователь нажимает кнопку ВПРАВО (RIGHT) или ВНИЗ (DOWN), GetNextDlgGroupItem возвращает следующий элемент управления, если этот элемент не имеет стиля WS_GROUP. В противном случае, функция меняет на противоположный порядок поиска и возвращает первый найденный элемент управления, который обладает стилем WS_GROUP. Если пользователь нажимает кнопки ВЛЕВО (LEFT) или ВВЕРХ (UP), функция возвращает значение предыдущего элемента управления, если текущий элемент управления уже имеет стиль WS_GROUP. Если текущий элемент управления имеет этот стиль, функция меняет порядок поиска на противоположный, определяет первый элемент управления, имеющий стиль WS_GROUP, и возвращает значение элемента управления, который непосредственно предшествовал найденному элементу управления.
Как только Windows получает следующий или предыдущий элемент управления, он передает в этот элемент сообщение WM_GETDLGCODE, которое определяет тип элемента управления. Затем Windows перемещает фокус ввода данных в элемент управления, если он не статический элемент управления. Если элемент управления — автоматическая «радио-кнопка», Windows передает для неё сообщение BM_CLICK. Прикладная программа также может использовать GetNextDlgGroupItem для определения элементов управления в группе.
Обычно, первый элемент управления в группе — это комбинация стилей WS_GROUP и WS_TABSTOP, так что пользователь может перемещаться из группы в группу при помощи кнопки TAB. Если группа содержит «радио-кнопки», прикладная программа должна применять стиль WS_TABSTOP только для первого элемента в группе. Windows автоматически перемещает стиль, когда пользователь перемещается между элементами управления в группе. Это гарантия того, что фокус ввода данных будет всегда у самого последнего выбранного элемента управления, когда пользователь перемещается в группе, используя кнопку TAB.
Мнемоника
(Замечание переводчика: Мнемоника — это совокупность приемов, облегчающих запоминание какой-либо информации.)
Мнемоника — это выбранная буква или цифра в названии кнопки или в тексте статического элемента управления. Windows перемещает фокус ввода в элемент управления, связанный с символом всякий раз, когда пользователь или нажимает кнопку, которая соответствует символу или нажимает совместно ALT и клавишу клавиатуры с этим символом. Мнемоника обеспечивает пользователю быстрый способ перемещения к данному элементу управления, используя клавиатуру.
Прикладная программа создает мнемонический символ для элемента управления, вставляя амперсант (&) непосредственно перед выбранной буквой или цифрой в названии или тексте элемента управления. В большинстве случаев, строка с символом нуля в конце, предоставленная элементом управления в шаблоне диалогового окна содержит амперсант. Однако, прикладная программа может создавать мнемонический символ в любое время, заменяя существующее название элемента управления или текст, при помощи использования функции SetDlgItemText. Каждому элементу управления может быть дан только один символ. Несмотря на то, что это рекомендовано, мнемоника в диалоговом окне не должна быть уникальной.
Когда пользователь нажимает на клавишу с буквой или цифрой, Windows сначала определяет, обрабатывает ли клавишу текущий элемент управления, имеющий фокус ввода данных. Windows посылает элементу управления сообщение WM_GETDLGCODE и, если элемент управления возвращает значение DLGC_WANTALLKEYS или DLG_WANTMESSAGE, Windows передает клавишу под управление этого элемента. В противном случае, она ищет элемент управления, мнемоника которого соответствует данной букве или цифре. Она продолжает искать до тех пор, пока не определит элемент управления или не проверит все элементы управления. В ходе поиска, она пропускает любые статические элементы управления, которые имеют стиль SS_NOPREFIX.
Если Windows определила статический элемент управления, а элемент управления не заблокирован, Windows перемещает фокус ввода данных в первый элемент управления после статического элемента управления, который является видимым, не заблокированным, и он имеет стиль WS_TABSTOP. Если Windows определяет какой-либо другой элемент управления, который имеет соответствующий символ, она перемещает фокус ввода в этот элемент управления. Если элемент управления — заданная по умолчанию командная кнопка, Windows посылает процедуре диалогового окна уведомительное сообщение BN_CLICKED. Если элемент управления — кнопка другого стиля и нет никаких других элементов управления в диалоговом окне, имеющих тот же самый мнемонический символ, Windows посылает сообщение BM_CLICK элементу управления.
Параметры настройки диалогового окна
Параметры настройки диалогового окна — текущий выбор и значения для элементов управления в диалоговом окне. Процедура блока диалога ответственна за инициализацию средств управления по этим параметрам настройки при создании диалогового окна. Она также ответственна за получение информации о текущих параметрах настройки от элементов управления перед разрушением блока диалога. Методы, используемые для инициализации и извлечения информации о параметрах настройки, зависят от типа элемента управления.
«Радио»-кнопки и окошки для отметки «галочкой»
Диалоговые окна используют «радио»-кнопки и окошки для отметок «галочкой», чтобы дать возможность пользователю выбрать параметр из списка. «Радио»-кнопки позволяют пользователю сделать выбор из взаимоисключающих параметров; окошки для отметки «галочкой» позволяют пользователю выбрать комбинацию параметров.
Процедура диалогового окна может установить начальное состояние окошка для отметки «галочкой», используя функцию CheckDlgButton, которая устанавливает или очищает окошко для отметки от «галочки». Для «радио»-кнопок в группе взаимоисключающих «радио»-кнопок, процедура диалогового окна может использовать функцию CheckRadioButton, чтобы установить соответствующую «радио»-кнопку и автоматически очистить любую другую «радио»-кнопку.
Прежде, чем диалоговое окно заканчивает свою работу, процедура блока диалога может проверить состояние каждой «радио»-кнопки и окошка для отметки «галочкой», используя функцию IsDlgButtonChecked, которая возвращает текущее состояние кнопки. Диалоговое окно обычно сохраняет эту информацию, чтобы инициализировать кнопки, в следующий раз, когда оно создает блок диалога.
Элементы управления диалогового окна Редактирование(Edit)
Много диалоговых окон имеют поля редактирования, которые позволяют пользователю давать текст в качестве вводимых данных. Большинство процедур диалогового окна инициализирует поля редактирования, когда блок диалога запускается первоначально. Например, процедура диалогового окна может поместить предложенное имя файла в элементе управления, которое пользователь может потом выбирать, изменять, или заменять. Процедура блока диалога может устанавливать текст в поле редактирования, используя функцию SetDlgItemText, которая копирует текст из данного буфера в поле редактирования. Когда поле редактирования принимает фокус ввода, оно автоматически выбирает законченный текст для редактирования.
Поскольку поля редактирования автоматически не возвращают свой текст диалоговому окну, процедура блока диалога должна восстановить текст прежде, чем она закончит свою работу. Она может восстановить текст, используя функцию GetDlgItemText, которая копирует текст поля редактирования в буфер. Процедура диалогового окна обычно сохраняет этот текст, чтобы инициализировать поле редактирования позже или передает его для обработки в родительское окно.
Некоторые диалоговые окна используют поля редактирования, которые позволяют пользователю вводить числа. Процедура блока диалога может извлечь число из поля редактирования, используя функцию GetDlgItemInt, которая извлекает текст из элемента редактирования и преобразует текст в десятичные значения. Пользователь вводит число десятичными цифрами. Оно может быть или знаковое или без знака. Процедура диалогового окна может отображать целое число, используя функцию SetDlgItemInt. Эта функция преобразует знаковое или беззнаковое целое число в строку десятичных цифр.
Окна со списком, комбинированные окна и списки каталогов
Некоторые диалоговые окна показывают списки названий, из которых пользователь может выбирать одно или несколько наименований. Например, чтобы показать список имен файлов, диалоговое окно обычно использует окно со списком и функции DlgDirList и DlgDirSelectEx. Функция DlgDirList автоматически заполняет окно со списком именами файлов в текущем каталоге. Функция DlgDirSelect извлекает информацию о выбранном имени файла в окне со списком. Вместе, эти две функции предоставляют удобный способ для диалогового окна, чтобы отобразить каталог, раскрытый таким образом, что пользователь может выбрать файл без необходимости вводить с клавиатуры его название и местоположение.
Диалоговое окно может также использовать комбинированный блок, чтобы отобразить список имен файлов. Функция DlgDirListComboBox автоматически заполняет часть окна со списком комбинированного блока с именами файлами в текущем каталоге. Функция DlgDirSelectComboBoxEx извлекает информацию о выбранном имени файла в части окна со списком.
Управляющие сообщения диалогового окна
Многие элементы управления опознают предопределенные сообщения, которые, когда они получены элементом управления, заставляет их выполнять некоторое действие. Например, сообщение BM_SETCHECK устанавливает «галочку» в окошке для отметки «галочкой», а сообщение EM_GETSEL извлекает информацию о части текста элемента управления, который в настоящее время выбран. Управляющие сообщения дают процедуре диалога больший и более гибкий доступ к элементам управления, чем стандартные функции, так что они часто используются тогда, когда диалоговое окно требует комплексного взаимодействия с пользователем.
Процедура диалогового окна может передать сообщение элементу управления, снабжая его идентификатором и используя функцию SendDlgItemMessage, которая является идентичной функции SendMessage, за исключением того, что она использует идентификатор элемента управления вместо дескриптора окна, чтобы идентифицировать элемент, который должен принять сообщение. Данное сообщение может потребовать, чтобы процедура блока диалога передала параметры сообщения, а сообщение должно иметь соответствующие возвращаемые значения. Действия и требования каждого управляющего сообщения зависят от цели сообщения и элемента управления, который обрабатывает его.
За более подробной информацией об управляющих сообщениях обратитесь к статье Элементы управления.
Пользовательские диалоговые окна
Прикладная программа может создать пользовательское диалоговое окно при помощи класса окна, определенного программой для этих блоков диалога, вместо использующегося предопределенного класса диалогового окна. Прикладные программы обычно используют этот метод, когда диалоговое окно — их главное окно, но он также полезен для создания модального и немодального блока диалога для приложений, которые имею обычные перекрывающиеся окна.
Определяемый программой класс окна позволяет прикладной программе определять оконную процедуру для блока диалога и обрабатывать сообщения перед посылкой их в процедуру диалогового окна. Он также позволяет приложению определить класс пиктограммы, класс кисти фона и класс меню для блока диалога. Прикладная программа должна зарегистрировать класс окна перед попыткой создать блок диалога, и должна обеспечить шаблон блока диалога значениями атомов или названием класса окна.
Много прикладных программ создают новый класс диалогового окна сначала извлекая информацию о классе для предопределенного класса блока диалога и передавая ее в функцию GetClassInfo, которая заполняет структуру WNDCLASS информацией. Прикладная программа модифицирует отдельные элементы структуры, такие как имена класса, кисти и пиктограммы, а затем регистрирует новый класс, используя функцию RegisterClass. Если прикладная программа самой себе заполняет структуру WNDCLASS, она должна установить элемент cbWndExtra в DLGWINDOWEXTRA, который является числом дополнительных байтов, котороеWindows требует для каждого блока диалога. Если прикладная программа к тому же использует дополнительные байты для каждого блока диалога, они должны быть вне дополнительных байтов, требуемых Windows.
Оконная процедура для пользовательского диалогового окна имеет те же самые параметры и требования, как и любая другая оконная процедура. В отличие от других оконных процедур, тем не менее, оконная процедура для этого диалогового окна должна вызвать функцию DefDlgProc вместо функции DefWindowProc для любых сообщений, которые она не обрабатывает. DefDlgProc выполняет обработку того же самого заданного по умолчанию сообщения, как и оконная процедура для предопределенного блока диалога, который включает вызов процедуры диалогового окна.
Прикладная программа может также создавать пользовательские диалоговые окна при помощи деления на подклассы оконной процедуры предопределенного блока диалога. Функция SetWindowLong позволяет прикладной программе установить адрес оконной процедуры для данного диалогового окна. Прикладная программа может также сделать попытку, используя функцию SetClassLong, поделить на подклассы, но сделав так, вы воздействуйте на все диалоговые окна в системе, принадлежащие не только этой прикладной программе.
Прикладная программа, которая создает пользовательские блоки диалога, иногда предусматривает замену взаимодействия клавиатуры с диалоговыми окнами. Для немодальных диалоговых окон это может означать то, что прикладная программа не вызывает функцию IsDialogMessage и вместо неё все введенные с клавиатуры данные обрабатывает в пользовательской оконной процедуре. В таком случае, прикладная программа может использовать сообщение WM_NEXTDLGCTL для минимизации кода, когда нужно переместить фокус ввода данных из одного элемента управления в другой. Это сообщение, когда передается в DefDlgProc, перемещает фокус ввода данных в определенный элемент управления и модернизирует внешний вид элементов управления, таких как перемещение границ командной кнопки по умолчанию или настройка автоматической радио-кнопки.
Использование диалоговых окон
Вы используйте блоки диалога, чтобы отобразить информацию и приглашение для ввода данных пользователем. Ваша прикладная программа загружает и инициализирует диалоговое окно, обрабатывает вводимые данные пользователем и разрушает блок диалога, когда пользователь завершает выполнение задачи. Способ обработки диалоговых окон различается, зависит от того, модальный или немодальный блок диалога. Модальное диалоговое окно требует, чтобы пользователь, перед активизацией другого окна в прикладной программе, закрыл диалоговое окно. Тем не менее, пользователь может активизировать окна в различных прикладных программах. Немодальное диалоговое окно не требует непосредственной реакции от пользователя. Оно похоже на главное окно, содержащее элементы управления. Разделы ниже обсуждают, как использовать оба типа диалоговых окон.
Отображение окна сообщений
Самая простая форма модального диалогового окна — окно сообщений. Большинство прикладных программ используют окна сообщений, чтобы предупредить пользователя об ошибках и подсказать направления, как действовать после того, как ошибка произошла. Вы создаете окно сообщений, используя функцию MessageBox или MessageBoxEx, определяя сообщение, и число и тип кнопок для показа. Windows создает модальное диалоговое окно, предоставляя свою собственные процедуру диалогового окна и шаблон. После того, как пользователь закрывает окно сообщений, функция MessageBox или MessageBoxEx возвращает значение идентифицирующее кнопку, выбранную пользователем при закрытии окна сообщений.
В примере ниже прикладная программа показывает окно сообщений, если переменная fError имеет значение ИСТИНА (TRUE). Это окно сообщений показывает описывающее ошибку сообщение. Стиль MB_OKCANCEL заставляет MessageBox снабдить окно двумя кнопками, которыми пользователь может выбирать, как ему поступить:
if (fError) {
if (MessageBox(hwndDlg, SZNOTFOUND, SZDELETEITEM,
MB_OKCANCEL)==IDOK)
.
. // подсказывает имя нового элемента и повторяет команду.
.
else
.
. // прекращение действия команды.
.
}
В этом примере, определяемые программой SZNOTFOUND и SZDELETEITEM, строки с нуль-терминатором в конце, которые обозначают текст сообщения и заголовок окна сообщений.
Создание модального диалогового окна
Вы создаете модальное диалоговое окно, используя функцию DialogBox. Вы должны определить идентификатор или имя ресурса шаблона диалогового окна и адрес процедуры блока диалога. Функция DialogBox загружает шаблон, показывает диалоговое окно и обрабатывает все вводимые пользователем данные, пока он не закроет блок диалога.
В примере ниже, прикладная программа показывает модальное диалоговое окно, когда пользователь в меню приложения выбирает команду Удалить элемент (Delete Item). Диалоговое окно содержит поле редактирования (в которое пользователь вводит имя элемента) и кнопки ОК и Отменить (Cancel). Управляющие идентификаторы для этих элементов управления, соответственно, ID_ITEMNAME, IDOK и IDCANCEL.
Первая часть примера состоит из операторов, которые создают модальное диалоговое окно. Эти операторы, в оконной процедуре для главного окна прикладной программы, создают блок диалога, когда система принимает сообщение WM_COMMAND, имеющее идентификатор команды IDM_DELETEITEM. Во второй части примера — процедура диалогового окна, которая извлекает содержимое поля редактирования и закрывает блок диалога при приеме сообщения WM_COMMAND.
Операторы ниже создают модальное диалоговое окно. Шаблон блока диалога — ресурс исполняемого файла прикладной программы и имеет идентификатором ресурса DLG_DELETEITEM:
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_DELETEITEM:
if (DialogBox(hinst,
MAKEINTRESOURCE(DLG_DELETEITEM),
hwnd, (DLGPROC)DeleteItemProc)==IDOK).
. // завершение работы команды; szItemName
. // содержит имя элемента
. // для удаления.
.
else
.
. // прерывание работы команды.
.
break;
}
return 0L;
В этом примере прикладная программа идентифицирует свое главное окно, как окно владелец для блока диалога. Когда Windows вначале показывает диалоговое окно, его расположение привязано к верхнему левому углу рабочей области окна владельца. Прикладная программа использует возвращаемое значение от DialogBox, чтобы установить, продолжать ли выполнение команды или прервать её работу. Ниже следующие операторы определяют процедуру диалогового окна.
char szItemName[80]; // принимает имя элемента, чтобы удалить.BOOL CALLBACK DeleteItemProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (!GetDlgItemText(hwndDlg, ID_ITEMNAME,
szItemName, 80))
*szItemName=0;
// потерпел неудачу.case IDCANCEL:
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
return FALSE;
}
В этом примере процедура использует GetDlgItemText, чтобы извлечь информацию о текущем тексте из поля редактирования, идентифицированном как ID_ITEMNAME. Затем процедура вызывает функцию EndDialog, чтобы установить возвращаемое значение диалогового окна, или IDOK или IDCANCEL, которое зависит от принятого сообщения и начинает работу по закрытию диалогового окна. Идентификаторы IDOK и IDCANCEL соответствуют кнопкам OK и Отменить (Cancel). После вызова процедурой EndDialog, Windows передает дополнительные сообщения для процедуры, чтобы разрушить блок диалога и возвращает значение диалогового окна назад в функцию, которая создавала блок диалога.
Создание немодального диалогового окна
Вы создаете немодальный блок диалога, используя функцию CreateDialog, определяя идентификатор или имя ресурса шаблона и адрес процедуры диалогового окна. CreateDialog загружает шаблон, создает диалоговое окно, но необязательно показывает его. Ваша прикладная программа ответственна за извлечение и диспетчеризацию сообщений о вводе пользователя в процедуре диалогового окна.
В следующем примере прикладная программа отображает немодальное диалоговое окно, если оно еще не отображено, когда пользователь выбирает команду Перейти к (Go To) из меню прикладной программы. Диалоговое окно содержит поле редактирования, окошко для отметки «галочкой» и кнопки OK и CANCEL. Шаблон блока диалога — ресурс в исполняемом файле прикладной программы и имеет идентификатор ресурса DLG_GOTO. Пользователь вводит номер строки в поле редактирования и проставляет в окошке для отметки «галочку», чтобы определить, что номер строки — относится к текущей строке. Идентификаторы элементов управления — ID_LINE, ID_ABSREL, IDOK и IDCANCEL.
Операторы в первой части примера создают немодальное диалоговое окно. Эти операторы, в оконной процедуре для главного окна прикладной программы, создают блок диалога, когда оконная процедура принимает сообщение WM_COMMAND, имеющее идентификатор команды IDM_GOTO, но только тогда, если глобальная переменная hwndGoto еще не содержит правильного дескриптора. Вторая часть примера — главный цикл сообщения прикладной программы. Цикл включает в себя функцию IsDialogMessage, чтобы гарантировать, что пользователь может использовать интерфейс клавиатуры блока диалога в этом немодальном диалоговом окне. Третья часть примера — процедура диалогового окна. Процедура извлекает информацию о содержимом поля редактирования и окошка для отметки «галочкой», когда пользователь выбирает кнопку OK. Процедура уничтожает диалоговое окно, когда пользователь выбирает кнопку Отменить (Cancel).
HWND hwndGoto = NULL; // дескриптор окна блока диалога.
.
.case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_GOTO:
if (!IsWindow(hwndGoto)) {
hwndGoto = CreateDialog(hinst,
MAKEINTRESOURCE(DLG_GOTO),
hwnd, (DLGPROC) GoToProc);
ShowWindow(hwndGoto, SW_SHOW);
}
break;
}
return 0L;
В предшествующих операторах, CreateDialog вызывается только тогда, если hwndGoto, не содержит правильный дескриптор окна. Это гарантирует, что прикладная программа одновременно не отобразит два диалоговых окна. Чтобы поддержать этот метод проверки, процедура блока диалога должна установить hwndGoto в значение ПУСТО (NULL), когда она уничтожает диалоговое окно.
Цикл сообщений для прикладной программы состоит из следующих операторов:
while (GetMessage(&msg, NULL, NULL, NULL))
{
if (!IsWindow(hwndGoto) || !IsDialogMessage(hwndGoto, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Цикл проверяет правильность дескриптора окна для блока диалога и только тогда вызывает функцию IsDialogMessage, если дескриптор правилен. Функция IsDialogMessage только тогда обрабатывает сообщение, если оно принадлежит диалоговому окну. Иначе, функция возвращает значение ЛОЖЬ(FALSE), а цикл посылает сообщение в соответствующее окно.
Следующие операторы определяют процедуру диалогового окна:
int iLine; // принимает номер строки
BOOL fRelative; // принимает состояние окошка для отметки "галочкой".
.
.BOOL CALLBACK GoToProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
BOOL fError;switch (message) {
case WM_INITDIALOG:
CheckDlgButton(hwndDlg, ID_ABSREL, fRelative);
return TRUE;case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
fRelative = IsDlgButtonChecked(hwndDlg,
ID_ABSREL);
iLine = GetDlgItemInt(hwndDlg, ID_LINE,
&fError, fRelative);
if (fError) {
MessageBox(hwndDlg, SZINVALIDNUMBER,
SZGOTOERR, MB_OK);
SendDlgItemMessage(hwndDlg, ID_LINE,
EM_SETSEL, 0, -1L);
} else
.
. // Уведомляет окно владельца, что команда выполнена.
.
return TRUE;case IDCANCEL:
DestroyWindow(hwndDlg);
hwndGoto = NULL;
return TRUE;
}
}
return FALSE;
}
В предшествующих операторах процедура обрабатывает сообщения WM_COMMAND и WM_INITDIALOG. В ходе обработки WM_INITDIALOG, процедура инициализирует окошко для отметки «галочкой», передавая текущее значение глобальной переменной fRelative в CheckDlgButton. Затем процедура возвращает значение ИСТИНА (TRUE), чтобы заставить Windows установить фокус ввода данных по умолчанию.
В ходе обработки WM_COMMAND, процедура закрывает диалоговое окно только тогда, если пользователь выбирает кнопку Отменить (Cancel) — то есть кнопку, имеющую идентификатор IDCANCEL. Процедура должна вызвать DestroyWindow, чтобы закрыть немодальное диалоговое окно. Обратите внимание, что процедура также устанавливает переменную hwndGoto в значение ПУСТО (NULL), чтобы гарантировать, что другие операторы, которые зависят от этой переменной, действуют правильно.
Если пользователь выбирает кнопку OK, процедура извлекает информацию о текущем состоянии окошка для отметки «галочкой» и присваивает ее переменной fRelative. Затем она использует эту переменную, чтобы извлечь данные о числе строк в поле редактирования. Функция GetDlgItemInt переводит текст в поле редактирования в целое число. Значение fRelative определяет, правильно ли понимает функция число как знаковое или беззнаковое значение. Если текст поля редактирования — не правильное число, GetDlgItemInt устанавливает в переменной fError значение отличное от нуля. Процедура проверяет это значение, чтобы определить, или показать сообщение об ошибке или завершить команду. В случае ошибки, процедура диалогового окна передает сообщение полю редактирования, предписывая ему выбрать текст в элементе управления так, чтобы пользователь мог его легко заменять. Если GetDlgItemInt не возвращает ошибку, процедура может или завершить затребованную команду самостоятельно или передать сообщение окну владельцу, предписывая ему завершить команду.
Инициализация диалогового окна
Вы инициализируйте диалоговое окно и его содержимое, когда обрабатывается сообщение WM_INITDIALOG. Самая общая задача состоит в том, чтобы инициализировать элементы управления, которые отражают текущие параметры диалогового окна. Другая общая задача состоит в том, чтобы поместить блок диалога в центр экрана или внутри окна его владельца. Полезная задача для некоторых диалоговых окон состоит в том, чтобы установить фокус ввода данных в обусловленный элемент управления, а не передать фокус ввода данных по умолчанию.
В примере ниже, процедура диалогового окна помещает блок диалога в центр и устанавливает фокус ввода данных, когда обрабатывается сообщение WM_INITDIALOG. Чтобы поместить диалоговое окно в центр, процедура извлекает данные о прямоугольниках окна блока диалога и окна владельца и просчитывает новую позицию диалогового окна. Чтобы установить фокус ввода данных, процедура проверяет параметр wParam, чтобы определить идентификатор фокуса ввода по умолчанию:
HWND hwndOwner;
RECT rc, rcDlg, rcOwner;case WM_INITDIALOG:
// Получим сведения о прямоугольниках окна владельца и окна диалога.
if ((hwndOwner = GetParent(hwndDlg)) == NULL)
hwndOwner = GetDesktopWindow();
GetWindowRect(hwndOwner, &rcOwner);
GetWindowRect(hwndDlg, &rcDlg);
CopyRect(&rc, &rcOwner);// Смещение прямоугольников владельца и диалогового окна такое,
// что правое и нижнее значения представляют собой ширину и
// высоту, а затем смещение окна владельца снова отбрасывается,
// чтобы уменьшить площадь блока диалога.OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
OffsetRect(&rc, -rc.left, -rc.top);
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);// Новая позиция, это - сумма половины оставшейся
// площади и исходной позиции окна владельца.SetWindowPos(hwndDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),
0, 0, // игнорирует параметры размера
SWP_NOSIZE);if (GetDlgCtrlID((HWND) wParam) != ID_ITEMNAME)
{
SetFocus(GetDlgItem(hwndDlg, ID_ITEMNAME));
return FALSE;
}
return TRUE;
В предшествующих операторах процедура использует функцию GetParent, чтобы извлечь дескриптор окна владельца блока диалога. Функция возвращает значение дескриптора окна владельца диалогового окна и дескриптор родительского окна дочерних окон. Поскольку прикладная программа может создать диалоговое окно, у которого нет владельца, процедура проверяет возвращаемые значения дескриптора и, если необходимо, использует функцию GetDesktopWindow, чтобы извлечь дескриптор самого главного окна. После расчета новой позиции, процедура использует функцию SetWindowPos, чтобы переместить диалоговое окно, установив значение HWND_TOP, которое гарантирует, что диалоговое окно останется в верхней части окна владельца.
Перед установкой фокуса ввода данных, процедура проверяет идентификатор элемента управления, в котором фокус ввода данных по умолчанию. Windows передает дескриптор окна, в котором фокус ввода данных по умолчанию, в параметр wParam. Функция GetDlgCtrlID возвращает идентификатор для элемента управления , который идентифицирован дескриптором окна. Если идентификатор не соответствует правильному идентификатору, процедура использует функцию SetFocus, чтобы установить фокус ввода данных. Функция GetDlgItem требует поиска данных о дескрипторе окна желаемого элемента управления.
Создание шаблона в памяти
Прикладные программы время от времени изменяют или модифицируют содержимое диалоговых окон, в зависимости от текущего состояния обрабатываемых данных. В подобных случаях не практично давать все возможные шаблоны диалогового окна как ресурсы в исполняемом файле прикладной программы. Однако создание шаблонов в памяти дает прикладной программе больше гибкости для адаптации к любым обстоятельствам.
В примере ниже прикладная программа создает шаблон в памяти для модального диалогового окна, которое содержит сообщение и кнопки ОК и Справка (Help).
В шаблоне блока диалога все символьные строки, такие как названия диалоговых окон и кнопок, должны быть строками Уникода. Этот пример использует функцию MultiByteToWideChar для создания этих строчек Уникода, поскольку и Windows NT и Windows 95 поддерживают MultiByteToWideChar.
Структуры DLGITEMTEMPLATE в шаблоне диалогового окна должны быть выровнены по границам ДВОЙНОГО СЛОВА (DWORD). Чтобы выровнять эти структуры, этот пример использует подпрограмму — помощника, которая получает введенный указатель, а возвращает самый близкий указатель, который выравнен по границе ДВОЙНОГО СЛОВА — DWORD (4 байта).
#define ID_HELP 150
#define ID_TEXT 200LPWORD lpwAlign ( LPWORD lpIn)
{
ULONG ul;
ul = (ULONG) lpIn;
ul +=3;
ul >>=2;
ul <<=2;
return (LPWORD) ul;
}LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner,
LPSTR lpszMessage)
{
HGLOBAL hgbl;
LPDLGTEMPLATE lpdt;
LPDLGITEMTEMPLATE lpdit;
LPWORD lpw;
LPWSTR lpwsz;
LRESULT ret;
int nchar;hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl)return -1;
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
// Определение диалогового окна.
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
| DS_MODALFRAME | WS_CAPTION;
lpdt->cdit = 3; // число элементов управления
lpdt->x = 10; lpdt->y = 10;
lpdt->cx = 100; lpdt->cy = 100;lpw = (LPWORD) (lpdt + 1);
*lpw++ = 0; // меню нет
*lpw++ = 0; // класс предопределенного диалогового окна (по умолчанию)lpwsz = (LPWSTR) lpw;
nchar = 1+ MultiByteToWideChar (CP_ACP, 0, "My Dialog", -1, lpwsz, 50);
lpw += nchar;//-----------------------
// Определение кнопки OK.
//-----------------------
lpw = lpwAlign (lpw); // выравнивание DLGITEMTEMPLATE по границе DWORD
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 70;
lpdit->cx = 80; lpdit->cy = 20;
lpdit->id = IDOK; // идентификатор кнопки OK
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // класс кнопкиlpwsz = (LPWSTR) lpw;
nchar = 1+MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
lpw += nchar;
lpw = lpwAlign (lpw); // выравнивание созданных данных по границе DWORD
*lpw++ = 0; // созданных данных нет//-----------------------
// Определение кнопки Help.
//-----------------------
lpw = lpwAlign (lpw); // выравнивание DLGITEMTEMPLATE по границе DWORDlpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_HELP; // идентификатор кнопки Help
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // атом класса кнопки
lpwsz = (LPWSTR) lpw;
nchar = 1+MultiByteToWideChar (CP_ACP, 0, "Help", -1, lpwsz, 50);
lpw += nchar;
lpw = lpwAlign (lpw); // выравнивание созданных данных по границе DWORD*lpw++ = 0; // созданных данных нет
//-----------------------
// Определение статического текста в элементе управления.
//-----------------------
lpw = lpwAlign (lpw); // выравнивание DLGITEMTEMPLATE по границе DWORD
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_TEXT; // идентификатор текста
lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0082; // класс статического элементаfor (lpwsz = (LPWSTR)lpw;
*lpwsz++ = (WCHAR) *lpszMessage++;
);
lpw = (LPWORD)lpwsz;
lpw = lpwAlign (lpw); // выравнивание созданных данных по границе DWORD
*lpw++ = 0; // созданных данных нетGlobalUnlock(hgbl);
ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
hwndOwner, (DLGPROC) DialogProc);
GlobalFree(hgbl);
return ret;
}