Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Поcобие_БЕЛОВ_Графический_интерфейс_API

.pdf
Скачиваний:
142
Добавлен:
18.03.2016
Размер:
2.75 Mб
Скачать

251

4) lpDialogFunc – указатель на функцию окна диалоговой панели.

Если функция окна панели успешно завершает свою работу, то функция DialogBoxIndirect возвращает значение nResult, заданное в вызове функции EndDialog, иначе возвращаемое значение равно -1.

Для разрушения созданной функцией DialogBoxIndirect панели вызывают функцию EndDialog:

BOOL EndDialog( HWND hdlg, int nResult);

Первым аргументом вызова функции EndDialog является дескриптор окна разрушаемой панели. Это значение первого параметра в заголовке функции окна панели.

Второй аргумент вызова функции EndDialog (nResult) определяет возвращаемое функцией DialogBoxIndirect значение.

Функция окна может вызвать эту функцию даже при обработке сообщения WM_INITDIALOG. При успешном разрушении панели функция EndDialog возвращает ненулевое значение. При ее вызове управление возвращают системе. Если цикл обработки сообщений панели закрыт, система разрушает панель и передает значение nResult как результат разрушения панели.

6.2.2. Создание немодальной диалоговой панели

Для создания немодальной диалоговой панели вызывают функцию CreateDialogIndirect:

HWND CreateDialogIndirect(HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate,

HWND hWndParent, DLGPROC lpDialogFunc);

Список ее формальных параметров подобен списку параметров функции DialogBoxIndirect, но она возвращает дескриптор окна созданной панели. Функция CreateDialogIndirect отображает панель, только если ее стиль в шаблоне содержит константу WS_VISIBLE.

6.2.3. Шаблон диалоговой панели

Шаблон диалоговой панели создают с помощью структур двух типов: DLGTEMPLATE и DLGITEMTEMPLATE. В начало шаблона записывают структуру типа DLGTEMPLATE. Она задает габариты, стиль и число элементов управления панели. Затем в шаблон записывают значения нескольких структур типа DLGITEMTEMPLATE. Их число равно числу элементов управления панели.

252

Структура DLGTEMPLATE описана следующим образом: typedef struct

{DWORD style;

DWORD dwExtendedStyle; WORD edit;

short x; short y; short ex;

short cy;

}DLGTEMPLATE;

Назначение полей структуры DLGTEMPLATE:

1)style задает стиль диалоговой панели. Значение этого поля задают с помощью констант с префиксом WS_ (типа WS_CAPTION и WS_ SYSMENU) и HDS_ (HDS_MODALFRAME, HDS_CONTROL);

2)dwExtendedStyle позволяет задавать расширенные стили для окна. Это поле не используется для создания шаблона диалоговой панели. Его значение может быть использовано для создания окон других стилей.

edit равно числу элементов управления панели; х задает координату левого края панели; у задает координату верхнего края панели; сх задает ширину панели; су задает высоту панели.

Поля х, у, сх, су задают в единицах диалоговых панелей.

В шаблоне панели после структуры DLGTEMPLATE записывают строки с именем меню, с именем класса и с текстом заголовка панели. Если в стиле панели указана константа DS_SETFONT, то за этими строками записывают 16-разрядное значение размера шрифта и строку с именем шрифта. Массивы строк меню, имена класса, заголовка и имена шрифта должны быть выровнены по границе WORD. Для выравнивания удобно пользоваться функцией следующего вида:

LPWORD lpwAlign(LPWORD lpln)

{ULONG ul = (ULONG)lpIn;

id +=3; ul >>=2;

ul <<=2;

return (LPWORD)ul;

 

}

Эта функция получает указатель lpln на массив элементов типа WORD и возвращает ближайший указатель, выровненный по границе

WORD.

253

Строка с именем меню идентифицирует ресурс меню для панели. Операционная система истолковывает содержимое этой строки в зависимости от значения ее первого элемента. При этом различают 3 значения первого элемента:

1)равен 0x0000. Шаблон не подключает ресурса меню к панели;

2)равен 0xFFFF. Шаблон подключает ресурс меню к панели. Порядковый номер этого ресурса меню содержится во втором элементе строки. Других элементов в строке не должно быть;

3)равен любому другому значению. Строку обрабатывают как строку Unicode, которая содержит имя ресурса меню.

Обычно исходную строку задают как Ansi-строку. Для ее преобразования в строку Unicode 16-битовых символов можно использовать функцию следующего вида:

int nCopyAnsiToWideChar (LPWORD lpWCStr, LPSTR lpAnsiln) { int cchAnsi=lstrlen(lpAnsiln);

return MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, lpAnsiln, cchAnsi, lpWCStr, cchAnsi)

+1; }

Параметр lpAnsiln этой функции принимает исходную Ansiстроку. Функция копирует ее в строку 16-битовых символов lpWCStr и возвращает число символов в строке lpWCStr + 1.

Строка имени класса задает класс окна панели. Операционная система истолковывает ее содержимое в зависимости от значения первого элемента. При этом различают 3 значения первого элемента:

1)равен 0x0000. Система использует предопределенный класс диалоговых окон;

2)равен 0xFFFF. Система использует предопределенный класс окон. Порядковый номер этого класса содержится во втором элементе строки. Других элементов в строке не должно быть;

3)равен любому другому значению. Строку обрабатывают как строку Unicode, которая содержит имя зарегистрированного класса.

Строка заголовка задается строкой Unicode. Если ее первый элемент равен 0x0000, то панель не имеет заголовка, а строка не содержит других элементов.

Размер шрифта определяет размер шрифта панели. Строка имени шрифта – это строка Unicode с именем используемого в панели шрифта.

Пример. Разработать функцию для записи значения структуры типаDLGTEMPLATE в шаблон панели. '

254

Решение этой задачи может быть описано в виде

void DlgTemplate(PWORD& p, DWORD IStyie, int items,

 

int x, int y, int ex, int cy, LPSTR txt)

{

*p++ = LOWORD(IStyle);

//В первые два слова

 

*p++ = HIWORD(IStyle);

//записываем стиль панели

 

*p++ = 0;

 

//В следующие две строки можно

 

*р++ = 0;

//записать расширенный стиль окна

 

*р++ = items;

//Число элементов управления панели

 

*р++ = х;

//Координата левого края панели

 

*р++ = у;

//Координата верхнего края панели

 

*р++ = сх;

//Ширина панели

 

*р++ = су;

//Высота панели

 

*р++ = 0;

//Меню не подключается

 

*р++ = 0;

//Используем стандартный класс

//Преобразуем Ansi-строку заголовка в строку Unicode int nchar=nCopyAnsiToWideChar(p,TEXT(txt));

р += nchar; //Смещаем указатель на количество символов //Выравниваем шаблон по границе WORD p=lpwAlign((LPWORD)p);

}

Как пользоваться этой функцией?

Заполнение начала шаблона панели значением структуры типа DLGTEMPLATE содержит следующие обязательные шаги:

1.Описать два указателя на массив элементов типа

WORD:WORD *p, *pdlgtemplate;

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

pdlgtemplate=p=(PWORD)LocalAlloc(LPTR,500);

3.Вызвать функцию DlgTemplate:

DlgTemplate(

 

р,

//Указатель на начало выделенного блока памяти

IStyle,

//Стиль диалоговой панели

7,

//Число элементов управления

20,

//Координата левого края диалоговой панели

20,

//Координата верхнего края диалоговой панели

100,

//Ширина

80,

//Высота

TEXT(str)); //Заголовок

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

255

Так, стиль панели можно было бы описать следующим образом:

DWORD IStyle = DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU;

Так же просто можно было описать строку заголовка: char str[ ] = "Пример диалоговой панели";

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

WORD *p, *pdlgtemplate; pdlgtemplate=p=(PWORD)LocalAlloc(LPTR,500); DlgTemplate(p, IStyle, 7,20, 20,100, 80, TEXT(str));.

Кроме данной возможности, реализована возможность динамического создания диалоговых панелей. После записи значения структуры типа DLGTEMPLATE в шаблон панели записывают указанное число значений структур типа DLGITEMTEMPLATE. Каждая такая структура задает габариты и стиль одного элемента управления панели. И каждая такая запись значения в шаблоне должна быть выровнена по границе DWORD.

Структура DLGITEMTEMPLATE описана следующим образом: typedef struct

{DWORD style;

DWORD dwExtendedStyie; short x;

short y; short ex;

short cy; WORD id;

} DLGITEMTEMPLATE;

Назначение полей этой структуры:

1)style определяет стиль элемента управления. Значение этого поля может быть комбинаций значений стиля окна (типа WS_BORDER) и стиля элемента управления (типа BS_PUSHBUTTON и ES_LEFT);

2)dwExtendedStyie задает расширенные стили для окна. Это поле для задания элементов управления панели не используют, но оно может быть использовано для создания других типов окон;

3)х задает координату в диалоговых единицах левого края элемента управления в панели;

4)у задает координату в диалоговых единицах верхнего края элемента управления в панели;

256

5)сх – ширина элемента управления;

6)су – высота элемента управления;

7)id – идентификатор элемента управления. Это значение содержится в младшем слове параметра wParam при поступлении в функцию окна панели сообщения WM_COMMAND от этого элемента управления.

После каждой записи значения типа DLGITEMTEMPLATE следуют строки имени класса, заголовка и дополнительных данных создания элемента управления. Причем каждая строка состоит из одного или более 16-разрядных значений. Строки имени класса и заголовка должны быть выровнены по границе WORD, а массив данных должен быть выровнен по границе DWORD.

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

Номер

Имя класса

Номер

Имя класса

Номер

Имя класса

0x0080

"button"

0x0082

"static"

0x0084

"scrollbar"

0x0081

"edit"

0x0083

"listbox"

0x0085

"combobox"

Строка заголовка содержит текст заголовка или идентификатор ресурса управления. Если ее первый элемент равен OxFFFF, должен быть еще один элемент, который определяет порядковый номер ресурса или идентификатор статического элемента управления – пиктограммы. Если первый элемент строки отличен от OxFFFF, система обрабатывает ее как строку Unicode с текстом заголовка или начального текста (например, редактора).

Массив данных создания может иметь любой размер и формат. Если первое слово этого массива отлично от нуля, то оно равно размеру данных в байтах плюс 4 байта первого элемента. Данные должны быть согласованы с функцией окна элемента управления, т. е. функция должна быть способна интерпретировать данные. При создании элемента управления система передает указатель на эти данные в параметре lParam сообщения WM_CREATE.

Пример. Разработать функцию для записи значения структуры типа DLGITEMTEMPLATE в шаблон панели.

Решение этой задачи может быть описано в виде

257

void DlgItemTemplate(PWORD& p, DWORD IStyle,

int x, int у, int ex, int cy, WORD id, LPSTR classname, LPSTR txt)

{

*p++ = LOWORD(IStyle);

// В первые два слова

 

*p++ = HIWORD(IStyle); //записываем стиль элемента

управления

 

 

 

*р++ = 0;

//В следующие две строки можно

 

*р++ = 0;

//записать расширенный стиль окна

 

*р++ = х;

//Координата левого края элемента

управления

 

 

 

*р++ = у;

//Координата верхнего фая элемента

управления

 

 

 

*р++ = сх;

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

 

*р++ = су;

//Высота элемента управления

 

*р++ = id;

//Идентификатор элемента управления

 

//Преобразуем Ansi-строку имени класса в строку Unicode

 

nt nchar= nCopyAnsiToWideChar( p, TEXT( classname));

 

p += nchar;

//Смещаем указатель на количество

символов

 

 

 

//Преобразуем Ansi-строку заголовка в строку Unicode

 

if (!strlen( txt) > 0)

 

 

nchar = nCopyAnsiToWideChar( p, TEXT( txt)); else

 

nchar = nCopyAnsiToWideChar(p,TEXT(""));

 

p += nchar;

//Смещаем указатель на число символов

 

*р++ = 0;

//Дополнительные данные не используем

//Выравниваем шаблон по границе WORD p=lpwAlign((LPWORD)p);

}

Как видно, эта функция полностью повторяет описание структуры DLGITEMTEMPLATE.

Как пользоваться этой функцией?

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

char statictext[]="Сейчас следует:"; //Текст элемента управления Height=height; //Высота статического элемента

IStyle = SS_LEFT | WS_CHILD | WS_VISIBLE; DlgItemTemplate(

р,

//Указываем на то место блока памяти,

//куда записать шаблон элемента управления

IStyle,

//Стиль

 

258

left,

//Координата левого края элемента управления

top,

//Координата верхнего края элемента управления

(lstrlen(statictext))*cxChar*4/dlgwunit, //Ширина

Height,

//Высота

ID_STATIC1,

//Идентификатор элемента управления

TEXT("static"), //Имя класса TEXT(statictext)); //Заголовок

Задача. В центре экрана создать модальную диалоговую панель с заголовком «Изменение режима работы приложения». Панель содержит группу с именем «Сейчас следует» зависимых переключателей с именами «Завершить работу приложения», «Перезагрузить данные» и «Сменить имя пользователя», а также 3 кнопки: «Да», «Отмена» и «Справка».

Листинг 6.1. Создание диалоговой панели.

#include <windows.h>

 

#include "CreateDig.h"

 

#define

ID_STATIC

2000

#define

ID_BUTTON1

2001

#define

ID_BUTTON2

2002

#defme

ID_BUTTON3

2003

#define

ID_HELP

2004

BOOL

RegClass(WNDPROC, LPCTSTR, UINT);

LRESULT

CALLBACK

WndProc(HWND,UINT,WPARAM,LPARAM);

LRESULT

CALLBACK DlgProc(HWND,UINT,

WPARAM, LPARAM); int CreateDlg(HWND); HINSTANCE hInstance;

char szClass[]="WindowAppClass";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)

{MSG msg; HWND hwnd; :;hInstance=hInstance;

if (!RegClass(WndProc,szClass,COLOR_DESKTOP)) return FALSE;

int wScreen=GetSystemMetrics(SM_CXSCREEN); int hScreen=GetSystemMetrics(SM_CYSCREEN);

hwnd = CreateWindow(szClass, "Создание диалоговой панели", WS_OVERLAPPEDWINDOW | WS_VISIBLE,

0,0, wScreen, hScreen, 0,0, hInstance, NULL);

259

if (!hwnd) return FALSE; while(GetMessage(&msg, 0,0,0))

{TranslateMessage(&msg);

DispatchMessage(&msg);

} return msg.wParam;

}

BOOL RegC1ass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)

{WNDCLASS wc; wc.style=wc.cbClsExtra=wc.cbWndExtra=0; wc.lpfnWndProc=Proc; wc.hInstance = hInstance; wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(brBackground +1); wc.lpszMenuName = (LPCTSTR)NULL; wc.lpszClassName=szName;

return (RegisterClass(&wc) != 0);

}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{switch (msg)

{case WM_LBUTTONDOWN:

{CreateDlg(hwnd); return 0;} case WM_DESTROY:

{PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

int CreateDlg( HWND hwnd)

{ char const caption[ ]=" Изменение режима работы приложения";

char const stattxt[ ]="Сейчас следует:";

char const modeoff[ ]="Завершить работу приложения"; char const modedat[ ]="Перезагрузить данные";

char const modepsw[ ]="Сменить имя пользователя"; //Выделяем блок памяти для записи шаблона

WORD *p, *pdlgtemplate; pdlgtemplate=p=(PWORD)LocalAlloc(LPTR,2000); //Определяем среднюю ширину cxChar и высоту cyChar

шрифта int cxChar, cyChar;

 

260

{

TEXTMETRIC tm; HDC hdc=GetDC(hwnd);

 

GetTextMetrics(hdc,&tm); ReleaseDC(hwnd,hdc);

 

cxChar=tm.tmAveCharWidth+1;

 

cyChar=tm.tmHeight+tm.tmExternalLeading;

}

//Определяем диалоговые единицы ширины и высоты

DWORD dlgunit =GetDialogBaseUnits(); int dlgwunit=LOWORD(dlgunit), dlghunit=HIWORD(dlgunit);

//Пересчитываем габариты символов шрифта cxChar=cxChar*4/dlgwunit;cyChar=cyChar*8/dlghunit; int wDIg, hDIg, wItem, hItem, left, top;

//Записываем в шаблон данные панели

DWORD IStyle = DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION;

wDlg=lstrien(caption)*cxChar; hDlg=cyChar*10; DlgTemplate(p, IStyle, 7, 0, 0, wDIg, hDIg, (LPSTR)caption);

//Далее добавляем записи элементов управления

//1

hItem=cyChar; top=left=hItem/2; hItem+=left; wItem=(wDlg-left-left);

IStyle = WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP;

DlgItemTemplate(p, IStyle, left, top, wItem, 4*hItem+left, ID_STATIC, (LPSTR)"button",(LPSTR)stattxt);

//2

wItem=lstrlen(modeoff)*cxChar+10; top+=hItem; IStyle = BS_AUTORADIOBUTTON | WS_CHILD |

WS_VISIBLE | WS_TABSTOP;

DlgItemTemplate(p, IStyle, hItem, top, wItem, hItem, ID_BUTTON1, (LPSTR)"button", (LPSTR)modeoff); //3

wItem=lstrlen(modedat)*cxChar+10; top+=hItem; IStyle = BS_AUTORADIOBUTTON | WS_CHILD |

WS_VISIBLE;

DlgItemTemplate(p, IStyle, hItem, top, wItem, hItem, ID_BUTTON2, "button", (LPSTR)modedat);

//4

wItem=lstrlen(modepsw)*cxChar+10;