Основная неувязка, возникающая при написании WinAPI приложений - это неудобство ручного сотворения всех окон приложения. Требуется вызывать функцию CreateWindow для каждого (в том числе и дочернего) окна программки, а потом к тому же поменять шрифт в неких из их. Наилучшим на мой взор выходом из этой ситуации является внедрение ресурсов диалоговых окон (dialog box resources) для соэдания всех окон приложения. В этой статье я расскажу как это делается в Delphi на примере обычного приложения с одним основным и 2-мя (модальными) окнами.
Шаг 1. Создание ресурсов диалоговых окон
Для сотворения ресурсов я использовал редактор ресурсов из состава Borland C++ 5.02. В Borland Resource Workshop 4.5 все практически аналогично. Создаем главное окно, вот его код:
Код: 500 DIALOGEX 0, 0, 240, 117
EXSTYLE WS_EX_DLGMODALFRAME WS_EX_APPWINDOW WS_EX_CLIENTEDGE
STYLE DS_MODALFRAME DS_3DLOOK DS_CENTER WS_OVERLAPPED WS_VISIBLE WS_CAPTION
WS_SYSMENU WS_MINIMIZEBOX
CLASS "WndClass1"
CAPTION "Главное окно приложения"
MENU 300
FONT 8, "MS Sans Serif", 400, 0
LANGUAGE LANG_RUSSIAN, 0
{
CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP,
19, 94, 50, 14, WS_EX_CLIENTEDGE
CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP,
96, 94, 50, 14, WS_EX_CLIENTEDGE
CONTROL "Help", IDHELP, "BUTTON", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP,
172, 94, 50, 14, WS_EX_CLIENTEDGE
CONTROL "Группа", -1, "button", BS_GROUPBOX BS_RIGHT WS_CHILD WS_VISIBLE WS_GROUP,
20, 9, 100, 76
CONTROL "Кнопка 1", 105, "button", BS_AUTORADIOBUTTON WS_CHILD WS_VISIBLE WS_TABSTOP,
28, 21, 60, 12
CONTROL "Кнопка 2", 106, "button", BS_AUTORADIOBUTTON WS_CHILD WS_VISIBLE WS_TABSTOP,
28, 37, 60, 12
CONTROL "Кнопка 3", 107, "button", BS_AUTORADIOBUTTON WS_CHILD WS_VISIBLE WS_TABSTOP,
28, 53, 60, 12
CONTROL "ListBox1", 108, "listbox", LBS_NOTIFY LBS_SORT LBS_NOINTEGRALHEIGHT WS_CHILD
WS_VISIBLE WS_BORDER WS_TABSTOP,
132, 13, 92, 72
}
Направьте внимание на поле CLASS. В нем должно стоять то же значение, что и в поле lpszClassName записи TWndClassEx основной программки. В редакторе ресурсов значение этого поля можно поменять в окне параметров ресурса.
Два других окна создаются как обыденные ресурсы, потому их код я тут не привожу.
Шаг 2. Основная программка.
Текст программки в нашем случае несколько отличается от текста, к примеру, winmin. Регистрация оконного класса:
Код: wc.cbSize:=sizeof(wc);
wc.style:=cs_hredraw or cs_vredraw;
wc.lpfnWndProc:=@WindowProc;
wc.cbClsExtra:=0;
wc.cbWndExtra:=DLGWINDOWEXTRA;
wc.hInstance:=HInstance;
wc.hIcon:=LoadIcon(hInstance, 'MAINICON');
wc.hCursor:=LoadCursor(0,idc_arrow);
wc.hbrBackground:=COLOR_BTNFACE+1;
wc.lpszMenuName:=nil;
wc.lpszClassName:='WndClass1';
RegisterClassEx(wc);
Направьте внимание, что в поле cbWindowExtra стоит константа DLGWINDOWEXTRA, если б её там не было, нам не удалось бы сделать главное окно, основанное на ресурсе Dialog Box. Не считая того, в поле lpszClassName стоит то же значение, что и в соответственном поле описания ресурса окна.
Итак, класс сотворен и зарегистрирован, сейчас создаем главное окно из ресурса: MainWnd:=CreateDialog(hInstance, '#500', 0, nil);
Припоминаю, что '#500' означает имя ресурса окна. Не забудьте подключить откомпилированный файл сценария ресурса к программке с помощью директивы {$r...}
Шаг 3. Оконная функция. Оконная функция ничем не отличается от обыкновенной:
Код: function WindowProc(wnd:HWND; Msg: Integer; Wparam:Wparam; Lparam:Lparam):Lresult; stdcall;
var nCode, ctrlID, size: word;
pt: TPoint;
s: string;
Begin
case msg of
wm_command:
Begin
nCode:=hiWord(wParam);
ctrlID:=loWord(wParam);
case ctrlID of
IDHELP: begin
DialogBox(hInstance,'#501',wnd,@DialogFunc);
end;
IDOK: begin
DialogBoxParam(hInstance,'#503',wnd,@DialogFunc2, Integer(pd));
s:= 'Login: '+pd^.login;
s:= s + ' ' + 'Pass: '+pd^.pass;
ListBox_AddString(lb, s);
end;
IDCANCEL: begin
DestroyWindow(wnd);
end;
end;
End;
wm_destroy:
Begin
Dispose(pd);
postquitmessage(0); exit;
Result:=0;
End;
else Result:=DefWindowProc(wnd,msg,wparam,lparam);
end;
end;
Шаг 4. Цикл сбора сообщений. Цикл сбора сообщений следует поменять последующим образом, как при использовании немодальных диалоговых окон. Можно, правда, бросить все как есть, но тогда вы не можете использовать клавиатуру для перемещения меж дочерними окнами, использования кнопок "по умолчанию" и т.д. While GetMessage(Mesg,0,0,0) do
begin
if mainWnd<>0 then
if IsDialogMessage(mainWnd,Mesg) then continue;
TranslateMessage(Mesg);
DispatchMessage(Mesg);
end;
После нажатия кнопки "ОК" возникает очередное окно. Если в нем ввести текст и надавить "ОК", этот текст будет добавлен в Listbox.
|