logo
ОСиС-2014(Передача№1) / 1_ОперСистСети_ЛР_Методичка_2012 / ОС_ЛР-09-13-14 / LAB7 / LAB7

Окна диалога

В файле ресурса могут быть также описаны диалоговые окна программы. Диалоговые окна как правило предназначены для ввода пользователем данных, которые невозможно или неудобно вводить при помощи меню. Диалоговые окна содержат дочерние окна управления (кнопки, поля ввода текста, радио-кнопки и кнопки-флажки), в описании вида и положения которых и состоит описание диалога.

При описании диалога требуется задавать множество координат, и это неудобно делать вручную, а еще неудобнее редактировать такое описание. Кроме того, координаты в диалогах, описываемых в ресурсах, задаются не в физических пикселах, а в особой координатной сетке (с шагом 1/8 высоты шрифта диалога по вертикали и 1/4 ширины шрифта по горизонтали), из-за чего диалоги при разных разрешениях экрана выглядят примерно одинаково по размерам. Для облегчения процесса описания диалогов (как, впрочем, и меню) созданы различные инструменты, в частности такая функция есть в пакете Borland Resource Workshop. С его помощью можно "нарисовать" внешний вид окна диалога и затем сохранить в виде текстового описания ресурса или непосредственно в бинарном файле ресурса.

Для обеспечения функционирования диалога необходимо описать так называемую процедуру диалога, которая очень похожа на оконную процедуру. Принципиальное отличие между диалоговой процедурой и обычной оконной процедурой состоит в том, что ее вызов производится из настоящей оконной процедуры окна диалога, которая находится "в недрах" Windows; и диалоговой процедуре передаются не все сообщения, которые получает оконная процедура. Заголовок диалоговой процедуры должен быть следующим (имя процедуры — любое):

function DlgProc(hDlg: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): longint; stdcall;

Если функция обрабатывает сообщение, она должна возвращать ненулевое значение, иначе — 0. Сообщения, которые не обрабатываются, не должны передаваться ни в DefWindowProc, ни в DefDlgProc, так как их обработка и так сосредоточена в оконной процедуре диалога. Вызов DefDlgProc внутри диалоговой процедуры приводит к рекурсии (оттуда снова будет вызвана диалоговая процедура), в результате чего приложение намертво "подвешивает" операционную систему.

Процедура диалога обычно обрабатывает как минимум два сообщения: WM_INITDIALOG, которое посылается диалоговому окну при его инициализации, и WM_COMMAND — сообщения от дочерних окон управления.

Если в ответ на WM_INITDIALOG процедура диалога возвращает TRUE, то Windows дает фокус первому из элементов управления диалога (его хэндл передается в wParam); при инициализации диалога можно изначально дать фокус другому элементу управления с помощью функции SetFocus, при этом обработчик WM_INITDIALOG должен вернуть FALSE.

При попытке использовать SetFocus возникает проблема: так как диалоговое окно создается Windows, то в программе неизвестны хэндлы дочерних органов управления. Однако эту информацию можно легко получить, зная числовой идентификатор органа управления, задаваемый в файле ресурса, при помощи функции GetDlgItem:

function GetDlgItem(hDlg: THandle; id: integer): THandle;

Сообщения WM_COMMAND от дочерних окон управления и способы управления ими достаточно подробно рассмотрены в теоретическом материале к предыдущей работе.

Для посылки сообщений органам управления в API реализована функция

function SendDlgItemMessage(hDlg: HWND; nIDDlgItem: Integer; Msg: UINT; wParam: WPARAM; lParam: LPARAM): Longint;

работающая аналогично SendMessage, при этом получателем сообщения является дочернее окно диалога hDlg с идентификатором nIDDlgItem (при этом не требуется знать хэндл этого органа управления).

В окнах диалога Windows автоматически поддерживает интерфейс клавиатуры, позволяющий перемещать фокус от одного дочернего окна управления к другому при помощи клавиши Tab и клавиш управления курсором.

Диалог загружается и активизируется при помощи функции DialogBox. Возврат из этой функции не производится, пока в ответ на какое-либо событие в диалоговой процедуре не будет вызвана функция EndDialog, т.е. функция DialogBox активизирует модальный диалог.

function DialogBox(hInstance: HINST; lpTemplate: PChar; hWndParent: HWND; lpDialogFunc: pointer): Integer;

lpTemplate — Z-строка, содержащая имя ресурса диалога, hWndParent — хэндл окна-собственника диалога (обычно — главного окна программы, хотя можно указать 0), lpDialogFunction — указатель на процедуру диалога. Возвращаемое значение определяется программистом при вызове EndDialog внутри процедуры диалога.

function EndDialog(hDlg: HWND; nResult: Integer): BOOL;

hDlg — хэндл окна диалога (передается в процедуру диалога в качестве параметра), nResult — код завершения диалога, возвращаемый в вызывающую диалог программу. Определены некоторые стандартные коды, например ID_OK, ID_CANCEL, ID_ABORT, ID_IGNORE, ID_YES, ID_NO, ID_CLOSE. Диалог должен завершаться явным вызовом EndDialog в ответ на нажатие некоторой кнопки (обычно это Ok и Cancel), а также при получении диалоговой процедурой сообщения WM_CLOSE.

Существует возможность работать с немодальными диалоговыми окнами, используя для их создания функцию CreateDialog, однако этот вопрос здесь рассматриваться не будет.