Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

359

рабочей области родительского окна и на расстоянии 2,5 символов от ее верхнего края. Ширина окна диалога равна 40 символам, а высота – 10 символам.

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

Функция GetDialogBaseUnits позволяет определять размеры системного шрифта, которые используются менеджером окна диалога. Для стандартного монитора VGA (самого часто используемого видеоадаптера в Windows) функция GetDialogBaseUnits возвращает ширину символа равную 8 и высоту равную 16 единицам. Поскольку единицы окна диалога соответствуют 1/4 средней ширины символа и 1/8 его высоты, то каждая единица соответствует 2 пикселям монитора VGA. Если идея использования таких единиц измерения окна диалога временами кажется слишком абстрактной, то лучше просто запомнить это правило.

Инструкция STYLE шаблона напоминает поле стиля функции CreateWindow. Использование WS_POPUP и WS_DLGFRAME вполне обычно для модальных окон диалога, хотя в дальнейшем мы изучим несколько альтернативных идентификаторов.

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

control-type "text" id, xPos, yPos, xWidth, yHeight [, iStyle]

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

Идентификаторы CTEXT, ICON и DEFPUSHBUTTON используются исключительно в окнах диалога. Они являются сокращенной формой записи идентификаторов класса окна и стиля окна. Например, CTEXT показывает, что класс дочернего окна элементов управления — это "static", а стиль такой:

WS_CHILD | SS_CENTER | WS_VISIBLE | WS_GROUP

Если с идентификатором WS_GROUP мы сталкиваемся впервые, то стили окна WS_CHILD, SS_CENTER и WS_VISIBLE уже встречались нам в главе 8 при создании статических дочерних окон элементов управления в программе COLORS1.

Что касается значка, то текстовое поле — это имя ресурса значка в программе, который также определен в файле описания ресурсов программы ABOUT1. Текстовое поле кнопки — это тот текст, который появится внутри кнопки на экране. Этот текст аналогичен тексту, заданному во втором параметре функции CreateWindow, которая вызывается при создании в программе дочернего окна элемента управления.

Поле id представляет собой число, с помощью которого дочернее окно идентифицирует себя при посылке сообщений (обычно эти сообщения WM_COMMAND) своему родительскому окну. Родительским окном этих дочерних окон элементов управления является само окно диалога, которое посылает эти сообщения оконной процедуре, находящейся внутри Windows. Эта оконная процедура посылает эти сообщения процедуре диалогового окна, которая включается в вашу программу. Значения id аналогичны идентификаторам дочерних окон, которые использовались в функции CreateWindow при создании в главе 8 дочерних окон. Поскольку дочерние окна с текстом и значком не посылают сообщений обратно родительскому окну, эти значения для них устанавливаются равными —1. Значение id для кнопки устанавливается равным IDOK, который в заголовочных файлах Windows определяется как 1.

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

Инструкция DEFPUSHBUTTON шаблона окна диалога в дополнение к стилю окна, заданному ключевым словом

DEFPUSHBUTTON, включает в себя стиль окна WS_GROUP. О стиле WS_GROUP (и стиле WS_TABSTOP) будет рассказано несколько позже, при обсуждении второй версии рассмотренной ранее программы — ABOUT2.

Диалоговая процедура

Диалоговая процедура или процедура диалога программы обрабатывает сообщения, получаемые окном диалога. Хотя она очень сильно напоминает оконную процедуру, это не настоящая оконная процедура. Оконная процедура окна диалога находится в Windows. Эта оконная процедура вызывает вашу диалоговую процедуру, передавая ей многие из сообщений, которые получает сама. Здесь представлена процедура диалога программы ABOUT1:

360

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

switch(iMsg)

{

case WM_INITDIALOG : return TRUE;

case WM_COMMAND : switch(LOWORD(wParam))

{

case IDOK : case IDCANCEL :

EndDialog(hDlg, 0); return TRUE;

}

break;

}

return FALSE;

}

Параметры этой функции те же, что и параметры обычной оконной процедуры; как и оконная процедура, процедура диалога должна быть определена как функция типа CALLBACK. Хотя в качестве описателя окна диалога использовался описатель hDlg, вместо него можно при желании использовать hwnd. Обратите внимание на отличия между этой функцией и оконной процедурой:

Оконная процедура возвращает значение типа LRESULT; а процедура диалогового окна — значение типа BOOL (определяемое в заголовочных файлах Windows как int).

Если оконная процедура не обрабатывает какое-то сообщение, она вызывает DefWindowProc; процедура диалога, если она не обрабатывает сообщение, возвращает FALSE (0), а если обрабатывает, то TRUE (ненулевое значение).

Процедура диалога не обрабатывает сообщения WM_PAINT и WM_DESTROY. Процедура диалога не получит сообщения WM_CREATE; вместо этого она выполняет инициализацию при обработке специального сообщения WM_INITDIALOG.

Сообщение WM_INITDIALOG является первым сообщением, которое получает процедура диалога. Это сообщение посылается только процедурам диалога. Если процедура диалога возвращает TRUE, то Windows помещает фокус ввода на первое дочернее окно элемента управления, которое имеет стиль WS_TABSTOP (о котором будет рассказано при изучении программы ABOUT2). В нашем окне диалога первым дочерним окном элемента управления, которое имеет стиль WS_TABSTOP, является кнопка. С другой стороны, при обработке сообщения WM_INITDIALOG процедура диалога может использовать функцию SetFocus для того, чтобы установить фокус на одно из дочерних окон управления окна диалога, и тогда она должна вернуть значение

FALSE.

Единственным оставшимся сообщением, которое обрабатывает процедура окна диалога, является WM_COMMAND. Это то сообщение, которое элемент управления кнопка посылает своему родительскому окну тогда, когда либо на ней производится щелчок мышью, либо нажата клавиша <Spacebar> (пробел) и кнопка имеет фокус ввода. Идентификатор дочернего окна элемента управления (который в шаблоне окна диалога равен IDOK) находится в младшем слове параметра wParam. Для этого сообщения процедура диалога вызывает функцию EndDialog, которая сообщает Windows о необходимости закрытия окна диалога. Для всех остальных сообщений процедура диалога возвращает FALSE, сообщая оконной процедуре окна диалога внутри Windows, что процедура диалога программы не обрабатывает сообщение.

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

Вызов окна диалога

При обработке в WndProc сообщения WM_CREATE, программа ABOUT1 получает описатель экземпляра программы и сохраняет его в статической переменной:

hInstance =((LPCREATESTRUCT) lParam) -> hInstance;

Программа ABOUT1 обрабатывает те сообщения WM_COMMAND, в которых младшее слово параметра wParam равно IDM_ABOUT. Когда программа его получает, она вызывает функцию DialogBox:

DialogBox(hInstance, "AboutBox", hwnd, AboutDlgProc);

Для этой функции требуется описатель экземпляра (сохраненный при обработке сообщения WM_CREATE), имя окна диалога (как оно определено в файле описания ресурсов), описатель родительского окна окна диалога

361

(которым является главное окно программы) и адрес процедуры диалога. Если вместо имени шаблона окна диалога используется число, то с помощью макрокоманды MAKEINTRESOURCE его можно преобразовать в строку.

Выбор из меню пункта "About About1..." приводит к выводу на экран окна диалога, показанного на рис. 11.2. Закрыть это окно диалога можно, щелкнув на кнопке OK мышью, нажав клавишу <Spacebar> или <Enter>. При нажатии клавиш <Spacebar> или <Enter> в любом окне диалога, в котором имеется кнопка по умолчанию, Windows посылает диалоговой процедуре сообщение WM_COMMAND, в котором младшее слово параметра wParam равно идентификатору заданной по умолчанию кнопки.

Функция DialogBox, которая вызывается для вывода на экран окна диалога, не возвращает управление в WndProc до тех пор, пока окно диалога не будет закрыто. Возвращаемым значением функции DialogBox является второй параметр функции EndDialog, которая вызывается в процедуре диалога. (Это значение не используется в программе ABOUT1, но используется в программе ABOUT2.) Затем WndProc может передать управление

Windows.

Даже при выводе на экран окна диалога, WndProc может продолжать получать сообщения. Вы даже можете посылать в WndProc сообщения из процедуры диалога. Поскольку главным окном программы ABOUT1 является родительское окно всплывающего окна диалога, то вызов функции SendMessage в AboutDlgProc должен начинаться следующим образом:

SendMessage(GetParent(hDlg), ...);

Рис. 11.2 Окно диалога программы ABOUT1

Дополнительная информация о стиле окна диалога

Стиль окна диалога задается в строке STYLE шаблона окна диалога. Для программы ABOUT1 использовался стиль, который наиболее часто используется для модальных окон диалога:

STYLE WS_POPUP | WS_DLGFRAME

Однако вы можете также поэкспериментировать с другими стилями. Например, можно попытаться использовать такой стиль:

STYLE WS_POPUP | WS_CAPTION

Такой стиль позволяет создать окно диалога со строкой заголовка и обычной для окна рамкой. Строка заголовка дает возможность пользователю с помощью мыши перемещать окно диалога по экрану. Если используется стиль WS_CAPTION, то координаты х и у, задаваемые в инструкции DIALOG, являются координатами рабочей области окна диалога относительно верхнего левого угла рабочей области родительского окна. Строка заголовка будет располагаться выше координаты у.

При наличии строки заголовка следом за инструкцией STYLE в шаблоне окна диалога можно задать текст заголовка с помощью инструкции CAPTION:

CAPTION "Dialog Box Caption"

Можно сделать то же самое с помощью функции SetWindowText при обработке сообщения WM_INITDIALOG в процедуре диалога:

SetWindowText(hDlg, "Dialog Box Caption");

362

Кроме этого, при условии использования стиля WS_CAPTION с помощью стиля WS_SYSMENU к окну диалога можно добавить системное меню:

STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU

Такой стиль позволяет пользователю выбрать из системного меню опции Move или Close.

Добавление к стилю идентификатора WS_THICKFRAME дает возможность пользователю изменять размер окна диалога, хотя такое изменение размера для окон диалога является делом необычным. Аналогично обстоит дело и с идентификатором WS_MAXIMIZEBOX.

Инструкция STYLE не является необходимой. Если в шаблон не включать инструкцию STYLE или CAPTION, то по умолчанию задается следующий стиль:

WS_POPUP | WS_BORDER

Но окно такого стиля смотрится хуже. Идентификатор WS_DLGFRAME обеспечивает гораздо более привлекательные результаты. Если к инструкции STYLE добавить инструкцию CAPTION, то по умолчанию задается следующий стиль:

WS_POPUP | WS_CAPTION | WS_SYSMENU

Кроме этого, меню к окну диалога можно добавить с помощью следующей инструкции в шаблоне окна диалога:

MENU menu-name

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

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

Хотя оконная процедура окна диалога обычно находится внутри Windows, для обработки сообщений окна диалога можно использовать одну из собственных оконных процедур. Для этого в шаблоне окна диалога необходимо задать имя класса окна:

CLASS "class-name"

Это делается редко, но тем не менее именно такой подход применяется в представленной далее в этой главе программе HEXCALC.

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

Дополнительная информация об определении дочерних окон элементов управления

В шаблоне окна управления файла ABOUT1.RC, для определения трех типов дочерних окон элементов управления, которые появляются в окне диалога, использовалась сокращенная запись: CTEXT, ICON и DEFPUSHBUTTON. Можно использовать и другие идентификаторы. Каждый тип соответствует конкретному предопределенному классу окна и стилю окна. В представленной ниже таблице показаны соответствующие каждому типу дочерних окон элементов управления класс окна и стиль окна:

Тип элемента управления

Класс окна

Стиль окна

PUSHBUTTON

button

BS_PUSHBUTTON | WS_TABSTOP

DEFPUSHBUTTON

button

BS_DEFPUSHBUTTON | WS_TABSTOP

CHECKBOX

button

BS_CHECKBOX | WS_TABSTOP

RADIOBUTTON

button

BS_RADIOBUTTON | WS_TABSTOP

GROUPBOX

button

BS_GROUPBOX | WS_TABSTOP

LTEXT

static

SS_LEFT | WS_GROUP

CTEXT

static

SS_CENTER | WS_GROUP

RTEXT

static

SS_RIGHT | WS_GROUP

363

Тип элемента управления

Класс окна

Стиль окна

ICON

static

SS_ICON

EDITTEXT

edit

ES_LEFT | WS_BORDER | WS_TABSTOP

SCROLLBAR

scrollbar

SBS_HORZ

LISTBOX

listbox

LBS_NOTIFY | WS_BORDER | WS_VSCROLL

COMBOBOX

combobox

CBS_SIMPLE | WS_TABSTOP

Единственной программой, которая понимает эту краткую запись, является компилятор ресурсов (RC). Кроме показанных выше стилей окна, каждое из представленных дочерних окон элементов управления имеет стиль:

WS_CHILD | WS_VISIBLE

Для всех типов дочерних окон элементов управления, за исключением EDITTEXT, SCROLLBAR, LISTBOX и COMBOBOX, используется следующий формат инструкций, описывающих элементы управления:

control-type "text", id, xPos, yPos, xWidth, yHeight [, iStyle]

А для типов элементов управления EDITTEXT, SCROLLBAR, LISTBOX и COMBOBOX в формат инструкций определения не входит текстовое поле:

control-type id, xPos, yPos, xWidth, yHeight [, iStyle]

Вобеих этих инструкциях поле iStyle не является обязательным.

Вглаве 8 рассказывалось о правилах задания ширины и высоты предопределенных дочерних окон элементов управления. Полезно было бы вернуться к этой главе и к этим правилам, учитывая, что размеры, которые указываются в шаблонах окон диалога, всегда задаются в единицах 1/4 средней ширины символа и 1/8 его высоты.

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

CHECKBOX "text", id, xPos, yPos, xWidth, yHeight, BS_LEFTTEXT

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

CONTROL "text", id, "class", iStyle, xPos, yPos, xWidth, yHeight

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

PUSHBUTTON "OK", IDOK, 10, 20, 32, 14

можно использовать инструкцию:

CONTROL "OK", IDOK, "button", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 10, 20, 32, 14

При компиляции файла описания ресурсов две этих инструкции кодируются одинаково, как в файле с расширением .RES, так и в файле с расширением .EXE.

Если инструкция CONTROL используется в шаблоне окна диалога, нет необходимости включать в нее стили WS_CHILD и WS_VISIBLE. Windows включает их в стиль окна при создании дочерних окон. Кроме этого формат инструкции CONTROL облегчает понимание того, что делает менеджер окна диалога Windows, когда он создает окно диалога. Во-первых, как уже ранее говорилось, он создает всплывающее окно, родительское окно которого определяется описателем окна, заданным в функции DialogBox. Затем для каждой инструкции элемента управления в шаблоне диалога, менеджер окна диалога создает дочернее окно. Родительским окном каждого из этих дочерних окон управления является всплывающее окно диалога. Приведенная выше инструкция CONTROL преобразуется в вызов функции CreateWindow, которая выглядит следующим образом:

CreateWindow("button", "OK",

WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 10 * cxChar / 4, 20 * cyChar / 8,

32 * cxChar / 4,14 * cyChar / 8, hDlg, IDOK, hInstance, NULL);

где cxChar и cyChar — это ширина и высота символа системного шрифта в пикселях. Параметр hDlg является возвращаемым значением функции CreateWindow, которая создает окно диалога. Параметр hInstance получен при первом вызове функции DialogBox.

Соседние файлы в предмете Операционные системы