Win32 API. Диалоговые окна

ОГЛАВЛЕНИЕ

В 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).

Заголовок шаблона.

В обоих шаблонах диалогового окна, стандартном и расширенном, заголовок включает в себя следующую общую информацию:

  1. Размещение и габариты диалогового окна.
  2. Стили окна и блока диалога для диалогового окна.
  3. Число элементов управления диалогового окна. Это значение обуславливается числом элементов управления DLGITEMTEMPLATE или DLGITEMTEMPLATEEX, которые определены в шаблоне.
  4. Необязательный ресурс меню для диалогового окна. Шаблон может указывать, что блок диалога не имеет меню, или он может установить значения по порядку, или строку Unicode с нуль-терминатором в конце, которые идентифицируют ресурс меню в исполняемом файле.
  5. Класс окна диалогового окна. Это может быть или предопределенный класс диалогового окна, или значения по порядку, или строка Unicode с нуль-терминатором в конце, которые идентифицируют зарегистрированный класс окна.
  6. Строка Unicode с нуль-терминатором в конце, которая определяет заголовок окна блока диалога. Если строка пустая, то поле заголовка диалогового окна не заполняется. Если в блоке диалога не определен стиль WS_CAPTION, система устанавливает заголовок, определенный в строке, но не показывает его.
  7. Если диалоговое окно имеет стиль DS_SETFONT, заголовок устанавливает размер в пунктах и название шрифта, который используется для текста в рабочей области и элементах управления блока диалога.

В расширенном шаблоне заголовок DLGTEMPLATEEX определяет к тому же следующую дополнительную информацию:

  1. Идентификатор контекста справки, который идентифицирует окно блока диалога, когда система посылает сообщение WM_HELP.
  2. Если в диалоговом окне определен стиль DS_SETFONT, заголовок устанавливает толщину шрифта и является ли шрифт курсивным (italic).

Определения элементов управления

Нижеследующий шаблон заголовка – это один или большее количество определений элементов управления, которые описывают элементы управления диалогового окна. И в стандартном и расширенном шаблоне, заголовок блока диалога имеет элемент, который указывает число элементов управления, определяемых в шаблоне. В стандартном шаблоне, каждое определение элемента управления, состоит из структуры DLGITEMTEMPLATE, сопровождаемой дополнительными массивами переменной длины. В расширенном шаблоне, определения элемента управления используют формат DLGITEMTEMPLATEEX.

И в стандартном, и в расширенном шаблонах, определение элемента управления включает в себя следующую информацию:

  1. Размещение и габариты элемента управления.
  2. Стили окна и элемента управления для средств управления.
  3. Идентификатор элемента управления.
  4. Класс окна элемента управления. Это может быть или порядковые значения предопределенного класса системы, или строка Unicode с нуль-терминатором на конце, которая определяет имя зарегистрированного класса окна.
  5. Cтрока Unicode с нуль-терминатором на конце, которая определяет начальный текст элемента управления, или перечисление значений, которые идентифицируют ресурс, типа пиктограммы, в исполняемом файле.
  6. Необязательный переменной длины блок данных создания. Когда система создает элемент управления, она передает указатель на эти данные в параметре 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 200

LPWORD 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 по границе DWORD

lpdit = (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;
}