Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Microsoft Windows 3.1 для программиста

© Александр Фролов, Григорий Фролов
Том 12, М.: Диалог-МИФИ, 1993, 255 стр.

[Назад] [Содеожание] [Дальше]

3.1. Создание диалоговой панели

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

Разумеется, перед вызовом этих функций необходимо создать шаблон диалоговой панели. Это можно сделать, использовав один из описанных выше способов.

Помимо шаблона, перед созданием диалоговой панели вам следует определить специальную функцию диалога, в которую будут поступать сообщения от функции окна диалоговой панели (которые, в свою очередь, поступают туда от органов управления). Функция диалога похожа на функцию таймера (получающую сообщения от таймера). Так же, как и функция таймера (а также функция окна), функция диалога является функцией обратного вызова и должна быть описана с использованием ключевого слова _export. Вместо этого имя функции обратного вызова можно занести в раздел EXPORTS файла определения модуля.

Итак, для создания диалоговой панели вы должны предпринять следующие действия:

создать шаблон диалога;

определить функцию диалога;

вызвать одну из функций создания диалога.

Создание шаблона диалога

Для создания шаблона диалога лучше всего воспользоваться редактором диалога Borland Resource Workshop или Microsoft Dialog Editor. Опишем процесс создания диалога с помощью редактора диалога, входящего в состав приложения Resource Workshop.

Использование Resource Workshop

Запустите Resource Workshop и из меню "File" выберите строку "New project...". В появившейся диалоговой панели установите переключатель ".RC" и нажмите кнопку "OK". На экране появится окно, озаглавленное "untitled.rc". Это окно не содержит ни одной строки, так как мы создали новый файл ресурсов (вы можете создать шаблон диалоговой панели в уже существующем файле ресурсов, если из меню "File" выберите строку "Open project...").

Затем из меню "Resource" выберите строку "New...". На экране появится диалоговая панель "New Resource". В списке "Resource Type" выберите строку "DIALOG" и нажмите кнопку "OK". После этого в главном окне приложения появятся окна, озаглавленные как "DIALOG_1", "Caption", "Alignment", "Tools" (рис. 3.1).

Окно "DIALOG_1" - это создаваемая вами диалоговая панель. Заголовок окна можно изменить. Для этого сначала сделайте щелчок мышью по заголовку окна, а затем в окне "Caption" введите новое имя для заголовка и нажмите клавишу <Enter>.

Установите нужный вам размер диалоговой панели, изменив размер окна "DIALOG_1". Это можно сделать, перемещая границы или углы окна мышью.

Далее следует создать и расположить на поверхности диалоговой панели все необходимые органы управления. Для создания органа управления (а также изменения стиля диалоговой панели) можно воспользоваться меню "Control".

Выберите из этого меню строку "Style...". На экране появится диалоговая панель "Window style" (рис. 3.2).

Рис. 3.2. Диалоговая панель "Window style"

В этой диалоговой панели вы можете изменить заголовок создаваемой диалоговой панели (поле "Caption"), класс окна ("Class"), который будет использоваться для диалоговой панели и даже подключить к диалоговой панели меню (поле "Menu"). Группа переключателей "Dialog style" позволяет изменить стиль диалоговой панели, добавив к ней системное меню ("System menu"), толстую рамку ("Thick frame"), вертикальную полосу просмотра ("Vertical scroll"), горизонтальную полосу просмотра ("Horizontal scroll"), кнопки минимизации ("Minimize Box") и максимизации ("Maximize box"), а также определить другие стили. Вы можете выбрать тип окна ("Window type"), стиль рамки ("Frame style") и шрифт ("Font..."). Однако пока мы рекомендуем вам использовать значения, установленные по умолчанию и показанные на рис. 3.2, изменив только заголовок диалоговой панели.

Остальные строки меню "Control" предназначены для создания органов управления.

Выберите из этого меню строку "Push button". Форма курсора при этом изменится. Курсор примет вид маленького крестика с нарисованной около него кнопкой "OK". Поместите курсор в то место диалоговой панели, в котором вам нужно создать кнопку и сделайте щелчок левой клавишей мыши. На поверхности диалоговой панели появится кнопка с надписью "Text". Размеры и расположение только что созданной кнопки можно изменять при помощи мыши.

Если сделать по кнопке двойной щелчок левой клавишей мыши, на экране появится диалоговая панель "Button styles", с помощью которой можно изменить атрибуты кнопки (рис. 3.3).

Рис. 3.3. Диалоговая панель "Button styles"

При помощи этой панели вы можете изменить текст, написанный на кнопке (поле "Caption"), выбрать стиль кнопки (группа переключателей "Button type"), а также определить другие атрибуты. Каждый орган управления, расположенный в диалоговой панели, должен иметь свой идентификатор. Этот идентификатор можно определить в поле "Control ID" в цифровом или символическом виде (в последнем случае файл описания ресурсов должен включать в себя файл с описанием символических имен идентификаторов органов управления).

Создав все органы управления и определив их атрибуты, сохраните шаблон диалоговой панели в файле описания ресурсов, для чего из меню "File" выберите строку "Save project" или "Save file as...".

Далее вы можете вносить изменения в шаблон при помощи любого текстового редактора. Можно также отредактировать готовый шаблон, запустив приложение Resource Workshop и загрузив шаблон, выбрав из меню "File" строку "Open project...".

Использование текстового редактора

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

Описание шаблона

Описание шаблона имеет следующий вид:

nameID DIALOG [load] [mem] x, y, width, height
CAPTION "Заголовок диалоговой панели"
STYLE   Стиль 
BEGIN      . . .
  . . .
  . . .
END

В этом описании nameID используется для идентификации шаблона диалоговой панели и может указываться либо в виде текстовой строки, либо в виде числа от 1 до 65535.

Параметр load - необязательный. Он используется для определения момента загрузки диалоговой панели в память. Если этот параметр указан как PRELOAD, диалоговая панель загружается в память сразу после запуска приложения. По умолчанию используется значение LOADONCALL, при использовании которого загрузка шаблона в память происходит только при отображении диалоговой панели.

Параметр mem также необязательный. Он влияет на тип выделяемой для хранения шаблона памяти и может указываться как FIXED (ресурс всегда остается в фиксированной области памяти), MOVEABLE (при необходимости ресурс может перемещаться в памяти, это значение используется по умолчанию) или DISCARDABLE (если ресурс больше не нужен, занимаемая им память может быть использована для других задач). Значение DISCARDABLE может использоваться вместе со значением MOVEABLE.

Параметры x и y определяют, соответственно, x-координату левой границы диалоговой панели и y-координату верхней стороны диалоговой панели. Координаты могут принимать значения от 0 до 65535.

Параметры width и height определяют, соответственно, ширину и высоту диалоговой панели. Эти параметры могут находиться в диапазоне от 1 до 65535.

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

Для описания шаблонов диалоговых панелей используется специальная координатная система, в которой размер единицы длины в пикселах зависит от размера системного шрифта. Такая координатная система позволяет создавать диалоговые панели, размер которых не зависит от режима работы видеоадаптера. Это возможно благодаря тому, что размер системного шрифта в пикселах зависит от разрешения - в режиме 800х600 точек размеры системного шрифта больше, чем, например, в режиме 640х480 точек.

Одна единица длины в координатной системе, используемой при описании ширины элементов шаблонов диалоговых панелей, составляет четверть средней ширины символов системного шрифта, а при описании высоты (или вертикальных размеров) - восьмую часть высоты символов системного шрифта. Так как высота символов системного шрифта примерно в два раза больше средней ширины этих символов, единица длины в этой системе координат имеет одинаковый размер по вертикали и горизонтали. Эта единица называется диалоговая единица (dialog unit).

Размер единицы измерения dialog unit можно получить при помощи функции GetDialogBaseUnits:

DWORD WINAPI GetDialogBaseUnits(void);

Младшее слово возвращаемого значения представляет собой ширину в пикселях диалоговой единицы длины, старшее - высоту.

Оператор CAPTION предназначен для определения заголовка диалоговой панели.

Оператор STYLE используется для назначения стиля окну диалоговой панели. В качестве стиля вы можете использовать комбинацию символических имен, определенных в файле windows.h и имеющих префикс WS_. Специально для диалоговых панелей в этом файле определены несколько констант с префиксом DS_.

Имя константы Описание
DS_LOCALEDIT При использовании этого стиля редакторы текста, созданные в диалоговой панели, будут использовать память в сегменте данных приложения. В этом случае можно использовать сообщения EM_GETHANDLE и EM_SETHANDLE
DS_MODALFRAME Создается модальная диалоговая панель (см. ниже)
DS_NOIDLEMSG Если этот стиль не указан, когда диалоговая панель переходит в видимое состояние (отображается), Windows посылает родительскому окну (создавшему диалоговую панель), сообщение WM_ENTERIDLE
DS_SYSMODAL Создается системная модальная диалоговая панель

Для создания стандартной диалоговой панели используются стили WS_POPUP, WS_BORDER, WS_SYSMENU, WS_CAPTION, DS_MODALFRAME. Если нужно создать диалоговую панель с рамкой, но без заголовка, используется стиль WS_DLGFRAME.

Отметим, что диалоговые панели бывают трех типов: модальные, системные модальные, и немодальные.

При выводе на экран модальной диалоговой панели работа приложения приостанавливается. Функции главного окна приложения и всех дочерних окон перестают получать сообщения от мыши и клавиатуры. Все эти сообщения попадают в временное (pop-up) окно диалоговой панели. Когда работа пользователя с диалоговой панелью будет завершена, главное окно приложения и его дочерние окна будут разблокированы. Заметьте, что диалоговая панель не должна создаваться как дочернее окно - в этом случае при активизации диалоговой панели она будет заблокирована наряду с остальными дочерними окнами и приложение "зависнет".

Модальная диалоговая панель, тем не менее, позволяет пользователю переключиться на работу с другими приложениями. Если вам требуется запретить такое переключение, используйте системные модальные диалоговые панели. Типичным примером такой панели является панель "Exit Windows", появляющаяся на экране перед завершением работы Windows. Пока эта панель находится на экране, вы не можете переключиться на работу с другими приложениями.

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

В наших первых примерах приложений с диалоговыми панелями мы будем использовать только модальные диалоговые панели.

Помимо операторов STYLE и CAPTION, описание шаблона может содержать операторы CLASS и FONT.

Оператор CLASS используется в тех случаях, когда диалоговая панель использует свой собственный класс, а не тот, который определен для диалоговых панелей операционной системой Windows:

CLASS "PrivateDlgClass"

В этом томе мы не будем рассматривать создание диалоговых панелей на базе собственных классов.

Перед созданием диалоговой панели с собственным классом этот класс должен быть зарегистрирован. При этом в структуре WNDCLASS, используемой для регистрации, поле cbWndExtra должно иметь значение DLGWINDOWEXTRA.

Оператор FONT позволяет задать шрифт, с использованием которого Windows будет писать текст в диалоговой панели:

FONT 10, "MS Serif"

Первый параметр оператора FONT указывает размер шрифта в пунктах, второй - название шрифта, определенного в файле win.ini. Отметим, что единственный шрифт, присутствие которого гарантируется - это системный шрифт. Все остальные шрифты можно отключить при помощи приложения Control Panel. Указывая шрифт, отличный от системного, вы не можете быть уверены, что этот шрифт будет установлен у пользователя. В этом случае перед выводом диалоговой панели имеет смысл убедиться в том, что в системе зарегистрирован требуемый шрифт (о том, как это сделать, вы узнаете позже). Если нужный шрифт не установлен, можно выдать предупреждающее сообщение.

Описание всех органов управления, расположенных на поверхности диалоговой панели, должно находиться между строками BEGIN и END.

Для описания органов управления используются три формата строк.

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

CtlType "Текст", ID, x, y, width, height [,style]

Вместо CtlType в приведенной выше строке должно находиться обозначение органа управления.

Параметр "Текст" определяет текст, который будет написан на органе управления.

Параметр ID - идентификатор органа управления. Этот идентификатор передается вместе с сообщением WM_CONTROL.

Параметры x и y определяют координаты органа управления относительно левого верхнего угла диалоговой панели. Используется единица длины dialog unit.

Параметры width и height определяют, соответственно, ширину и высоту органа управления в единицах длины dialog unit.

Параметр style определяет стиль органа управления (необязательный параметр). Это тот самый стиль, который указывается при вызове функции CreateWindow.

Приведем список обозначений органов управления и возможных стилей для первого формата.

Обозначение органа управления Класс окна Описание и стиль, используемый по умолчанию
CHECHBOX button Переключатель в виде прямоугольника BS_CHECKBOX, WS_TABSTOP
CTEXT static Строка текста, выровненная по центру SS_CENTER, WS_GROUP
DEFPUSHBUTTON button Кнопка, выбираемая в диалоговой панели по умолчанию BS_DEFPUSHBUTTON, WS_TABSTOP
GROUPBOX button Прямоугольник, объединяющий группу органов управления BS_GROUPBOX
ICON static ПиктограммаSS_ICON Параметры width, height и style можно не указывать
LTEXT static Строка текста, выровненная по левой границе органа управления SS_LEFT, WS_GROUP
PUSHBUTTON button КнопкаBS_PUSHBUTTON, WS_TABSTOP
RADIOBUTTON button Переключатель в виде кружка (радиопереключатель) BS_RADIOBUTTON, WS_TABSTOP
RTEXT static Строка текста, выровненная по правой границе органа управления SS_RIGHT, WS_GROUP

Стили WS_TABSTOP и WS_GROUP будут описаны позже.

Второй формат используется для описания списков, редакторов текста и полос просмотра:

CtlType ID, x, y, width, height [,style]

В этом формате нет параметра "Текст", остальные параметры используются так же, как и в первом формате.

Приведем список обозначений органов управления и возможных стилей для второго формата.

Обозначение органа управления Класс окна Описание и стиль, используемый по умолчанию
COMBOBOX combobox Список с окном редактирования CBS_SIMPLE, WS_TABSTOP
LISTBOX listbox Список LBS_NOTIFY, WS_BORDER
EDITTEX edit Редактор текста ES_LEFT, WS_BORDER, WS_TABSTOP
SCROLLBARS scrollbar Полоса просмотраSBS_HORZ

Третий формат описания органов управления наиболее универсальный:

CONTROL "Текст", ID, class, style, x, y, width, height

Этот формат позволяет описать орган управления, принадлежащий классу class, который указывается в виде строки символов. Вы можете использовать третий формат для описания предопределенных классов органов управления, таких как "button", "combobox", "edit", "listbox", "scrollbar", "static". Данный формат описания можно использовать для любых органов управления.

Функция диалога

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

BOOL CALLBACK _export
DlgProc (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);

Вы можете выбрать для функции диалога любое имя.

Параметры функции диалога напоминают параметры функции окна. Все они, за исключением первого, имеют аналогичное назначение. Через первый параметр функции диалога передается идентификатор диалога hdlg, а не идентификатор окна hwnd.

В отличие от функции окна, функция диалога не должна вызывать функцию DefWindowProc для тех сообщений, которые она не желает обрабатывать. Если функция диалога обрабатывает сообщение, она должна вернуть значение TRUE, а если нет - FALSE.

Функция диалога не обрабатывает сообщения WM_CREATE, WM_PAINT, WM_DESTROY. При инициализации диалога в функцию диалога вместо сообщения WM_CREATE передается сообщение WM_INITDIALOG. Как правило, функция диалога всегда обрабатывает сообщения WM_INITDIALOG и WM_COMMAND.

Сообщение WM_INITDIALOG использует параметры wParam и lParam.

Параметр wParam содержит идентификатор органа управления, который первым получит фокус ввода после отображения диалоговой панели. Это первый орган управления, описанный в шаблоне диалога со стилем WM_TABSTOP. Параметр lParam содержит значение, передаваемое приложением при создании диалоговой панели.

Если в ответ на сообщение WM_INITDIALOG функция диалога возвращает значение TRUE, после создания диалоговой панели фокус ввода передается органу управления, идентификатор которого был записан в параметре wParam.

Если при инициализации диалоговой панели обработчик сообщения WM_INITDIALOG устанавливает фокус ввода на другой орган управления (вызывая функцию SetFocus), функция диалога должна вернуть значение FALSE.

Сообщение WM_COMMAND, поступающее в функцию диалога, передает сообщения или извещения от органов управления, расположенных в диалоговой панели. Крое этого, функция диалога может получить это сообщение с параметром wParam, равным константам IDOK и IDCANCEL, описанным в файле windows.h.

Сообщение с параметром IDOK поступает в функцию диалога в том случае, если пользователь нажал клавишу <Enter> в момент, когда ни одна из кнопок, расположенных в диалоговой панели, не имеет фокус ввода, и ни одна из кнопок не имеет стиль WS_DEFPUSHBUTTON. Если в диалоговой панели есть кнопка со стилем WS_DEFPUSHBUTTON, в описанной ситуации в функцию диалога поступает сообщение WM_COMMAND с параметром wParam, равным идентификатору этой кнопки.

Сообщение с параметром IDCANCEL появится тогда, когда пользовательзакроет диалоговую панель с помощью системного меню или клавиши <Esc>.

Обычно в диалоговой панели всегда создается одна клавиша, имеющая стиль WS_DEFPUSHBUTTON. Как правило, на этой клавише пишется слово "OK" и она используется для нормального завершения работы диалоговой панели. Для этой клавиши имеет смысл использовать идентификатор IDOK.

Еще одна клавиша, присутствующая практически во всех диалоговых панелях, имеет надпись "Cancel" и используется для отмены диалоговой панели. Если определить идентификатор этой клавиши как IDCANCEL, вы сможете использовать единый обработчик сообщения для отмены диалоговой панели при помощи кнопки и при помощи системного меню или клавиши <Esc>.

Функции для создания диалоговой панели

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

Для создания модальной диалоговой панели чаще всего используется функция DialogBox:

int WINAPI DialogBox(
  HINSTANCE hInstance,
  LPCSTR lpszTemplate,
  HWND hwndOwner,
  DLGPROC dlgprc);

Через параметр hInstance необходимо передать идентификатор текущей копии приложения.

Параметр lpszTemplate представляет собой указатель на строку имени шаблона, указанном в операторе DIALOG текстового описания шаблона.

Параметр hwndOwner - идентификатор окна, создавшего диалоговую панель.

Последний параметр, dlgprc, представляет собой адрес функции диалога.

Если при создании диалоговой панели ей необходимо передать параметр, воспользуйтесь функцией DialogBoxParam:

int WINAPI DialogBoxParam(
  HINSTANCE hInstance,
  LPCSTR lpszTemplate,
  HWND hwndOwner,
  DLGPROC dlgprc,
  LPARAM lParamInit);

Эта функция полностью аналогична функции DialogBox, за исключением дополнительного параметра lParamInit. Значение этого параметра передается через параметр lParam сообщения WM_INITDIALOG и может быть проанализировано на этапе создания диалоговой панели.

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

Функция DialogBoxIndirect аналогична функции DialogBox, но в качестве второго параметра в ней используется не указатель на строку имени шаблона, а идентификатор глобального блока памяти, в котором подготовлен шаблон:

int WINAPI DialogBoxIndirect(
  HINSTANCE hInstance,
  HGLOBAL hglbDlgTemplate,
  HWND hwndOwner, DLGPROC dlgprc);

Функция DialogBoxIndirectParam аналогична функции DialogBoxIndirect, но имеет дополнительный параметр lParamInit:

int WINAPI DialogBoxIndirectParam(
  HINSTANCE hInstance, HGLOBAL hglbDlgTemplate,
  HWND hwndOwner, DLGPROC dlgprc,
  LPARAM lParamInit);

Для создания немодальных диалоговых панелей используются функции CreateDialog, CreateDialogParam, CreateDialogIndirect, CreateDialogIndirectParam. Эти функции имеют параметры, аналогичные параметрам функций DialogBox, DialogBoxParam, DialogBoxParamIndirect:

HWND WINAPI CreateDialog(HINSTANCE hInstance,
  LPCSTR lpszTemplate, HWND hwndOwner,
  DLGPROC dlgprc);

HWND WINAPI CreateDialogParam(HINSTANCE hInstance,
  LPCSTR lpszTemplate,  HWND hwndOwner,
  DLGPROC dlgprc, LPARAM lParamInit);

HWND WINAPI CreateDialogIndirect(HINSTANCE hInstance,
  HGLOBAL hglbDlgTemplate,
  HWND hwndOwner, DLGPROC dlgprc);

HWND WINAPI CreateDialogIndirectParam(
  HINSTANCE hInstance, HGLOBAL hglbDlgTemplate,
  HWND hwndOwner, DLGPROC dlgprc,
  LPARAM lParamInit);

Функции DialogBox, DialogBoxParam, DialogBoxIndirect, и DialogBoxIndirectParam возвращают значение, передаваемое при завершении работы диалоговой панели с помощью функции EndDialog.

Функция EndDialog имеет следующий прототип:

void WINAPI EndDialog(HWND hdlg, int nResult);

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

Функции CreateDialog, CreateDialogParam, CreateDialogIndirect, и CreateDialogIndirectParam возвращают идентификатор окна для созданной диалоговой панели.

Приложение DIALOG

Прежде чем двинуться дальше, рассмотрим приложение DIALOG, создающее простейшую диалоговую панель, похожую по внешнему виду на диалоговую панель, появляющуюся на экране при вызове функции MessageBox (рис. 3.4).

Рис. 3.4. Главное окно приложения DIALOG

В главном окне приложения имеется кнопка "About...". Если нажать на нее левой клавишей мыши, на экране появится диалоговая панель "Приложение DIALOG". На поверхности этой диалоговой панели мы разместили пиктограмму, статический орган управления и кнопку.

Вы можете завершить работу диалоговой панели, нажав на кнопку "OK" или отменив диалог с помощью системного меню или клавиши <Esc>.

Исходный текст главного файла приложения представлен в листинге 3.1.


Листинг 3.1. Файл dialog\dialog.cpp


// ----------------------------------------
// Простейшая диалоговая панель
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <mem.h>

#define IDB_Button1 1

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK    _export DlgProc(HWND, UINT, WPARAM, LPARAM);

// Имя класса окна
char const szClassName[]   = "DialogAppClass";

// Заголовок окна
char const szWindowTitle[] = "Dialog Box Demo";

HINSTANCE hInst;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine, 
        int       nCmdShow)   
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  HWND hButton1;

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  hInst = hInstance;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию 
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0,                   // идентификатор родительского окна
    0,                   // идентификатор меню
    hInstance,           // идентификатор приложения
    NULL);               // указатель на дополнительные
                         // параметры

  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Создаем кнопку
  hButton1 = CreateWindow("button", "About...",
    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    20, 20, 90, 30,
    hwnd, (HMENU) IDB_Button1,
    hInstance, NULL);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна

  memset(&wc, 0, sizeof(wc));

  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC) WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName = (LPSTR)NULL;
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static DLGPROC lpfnDlgProc;

  switch (msg)
  {
    case WM_COMMAND:
    {
      // Если нажата кнопка, выводим
      // диалоговую панель
      if(wParam == IDB_Button1)
      {
        // Переходник для функции диалоговой панели
        lpfnDlgProc = (DLGPROC) 
          MakeProcInstance((FARPROC)DlgProc, hInst);

        // Создаем модальную диалоговую панель
        DialogBox(hInst, "DIALOG_OK", hwnd, lpfnDlgProc);
      }
      return 0;
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция DlgProc
// =====================================
#pragma argsused

BOOL CALLBACK _export
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Инициализация диалоговой панели
    case WM_INITDIALOG:
    {
      return TRUE;
    }

    case WM_COMMAND:
    {
      switch(wParam)
      {
        // Сообщение от кнопки "OK"
        case IDOK:

        // Отмена диалоговой панели.
        // Это сообщение приходит, когда пользователь
        // нажимает на клавишу <Esc>
        case IDCANCEL:
        {
          // Устанавливаем флаг завершения диалога
          EndDialog(hdlg, 0);
          return TRUE;
        }
      }
    }
  }
  return FALSE;
}

Функция WinMain создает главное окно приложения и располагает в нем один орган управления - кнопку с надписью "About...". Эта кнопка предназначена для активизации диалоговой панели.

Функция главного окна приложения WndProc обрабатывает сообщение WM_COMMAND, поступающее от кнопки:

case WM_COMMAND:
{
  if(wParam == IDB_Button1)
  {
    lpfnDlgProc = (DLGPROC) 
      MakeProcInstance((FARPROC)DlgProc, hInst);

    DialogBox(hInst, "DIALOG_OK", hwnd, lpfnDlgProc);
  }
  return 0;
}

Прежде всего вызывается функция MakeProcInstance, создающая переходник для функции диалога DlgProc. Если вы пользуетесь современными средствами разработки, такими как Borland C++ for Windows версий 3.1 или 4.0 или Microsoft Visual C++, и если функция диалога описана с ключевым словом _export, переходник можно не создавать.

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

Функция диалоговой панели DlgProc обрабатывает сообщения WM_INITDIALOG и WM_COMMAND.

Обработчик сообщения WM_INITDIALOG состоит из одной строки, возвращающей значение TRUE. В этом случае после инициализации диалоговой панели фокус ввода передается первому органу управления, описанному в шаблоне со стилем WS_TABSTOP. В нашем случае это кнопка с надписью "OK":

DEFPUSHBUTTON "OK", IDOK, 56, 43, 36, 14,
    WS_CHILD | WS_VISIBLE | WS_TABSTOP

Обработчик сообщения WM_COMMAND в ответ на любые действия пользователя вызывает функцию EndDialog, предназначенную для завершения работы диалоговой панели:

case WM_COMMAND:
{
  switch(wParam)
  {
    case IDOK:
    case IDCANCEL:
    {
      EndDialog(hdlg, 0);
      return TRUE;
    }
  }
}

Листинг 3.2. Файл dialog\dialog.rc


#include "g:\tcwin\include\windows.h"

APPICON ICON "appicon.ico"

DIALOG_OK DIALOG 25, 34, 152, 67
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Приложение DIALOG"
BEGIN
  CTEXT "Microsoft Windows Application\n"
    "Приложение DIALOG\n"
    "(C) Frolov A.V., 1994",
    -1, 28, 9, 117, 26, WS_CHILD | WS_VISIBLE | WS_GROUP
  ICON "APPICON", -1, 6, 14, 16, 16, WS_CHILD | WS_VISIBLE
  DEFPUSHBUTTON "OK", IDOK, 56, 43, 36, 14,
    WS_CHILD | WS_VISIBLE | WS_TABSTOP
END

В файл описания ресурсов приложения мы включили файл windows.h, так как именно там описаны идентификаторы IDOK и IDCANCEL.

Перед шаблоном в файле ресурсов приложения описана пиктограмма с идентификатором APPICON (листинг 3.3), на которую есть ссылка в шаблоне диалоговой панели.


Листинг 3.3. Файл dialog\appicon.ico



Описание шаблона диалога начинается с оператора DIALOG. В этом операторе определено имя шаблона DIALOG_OK, на которое ссылается функция DialogBox.

При помощи оператора STYLE определен стиль диалога. Мы создаем модальный диалог (DS_MODALFRAME), созданный как временное окно (WS_POPUP), с заголовком (WS_CAPTION) и системным меню (WS_SYSMENU).

Заголовок диалоговой панели задан в операторе CAPTION.

Далее в описании шаблона между операторами BEGIN и END находятся строки описания органов управления.

Оператор CTEXT описывает статический орган управления. Обратите внимание на использование символа "\n" для принудительного перехода на новую строку.

Оператор ICON описывает пиктограмму.

Оператор DEFPUSHBUTTON описывает кнопку с надписью "OK". Эта кнопка - единственный орган управления, имеющий стиль WS_TABSTOP, поэтому при инициализации диалоговой панели ей передается фокус ввода.

Файл определения модуля приложения DIALOG приведен в листинге 3.4.


Листинг 3.4. Файл dialog\dialog.def


; =============================
; Файл определения модуля
; =============================
NAME DIALOG
DESCRIPTION 'Приложение DIALOG, (C) 1994, Frolov A.V.'
EXETYPE windows
STUB 'winstub.exe'
STACKSIZE 5120
HEAPSIZE 1024
CODE preload moveable discardable
DATA preload moveable multiple

[Назад] [Содеожание] [Дальше]