Создание кнопок средствами WinAPI
Создание кнопок средствами WinAPI
Создание кнопок средствами WinAPI Источник: http://decoding.narod.ru/api/button/button.html Сегодня мы поговорим о том, как создаются кнопки. За основу возьмем наш шаблон (если вы не читали статью "Минимальная программа на Win API", прочтите, именно с этим шаблоном мы будем работать). На некоторых кнопках нарисуем стандартные иконки, на некоторых выведем текст. И конечно обработаем событие, вызываемое нажатием на кнопку. Кроме этого, кнопки с текстом смогут иметь "фокус", который будет оставаться после нажатия на одну из них. Начнем с того, что для каждой кнопки создадим константу с уникальным идентификационным номером. Объявление самих кнопок удобнее всего сделать в виде массива, это сделает код более компактным. Также создадим переменные для работы с иконками и шрифтом. const // Кнопки, на которые будут выведены иконки BTN_APPLICATION = 0; BTN_HAND = 1; BTN_QUESTION = 2; BTN_EXCLAMATION = 3; BTN_ASTERISK = 4; BTN_WINLOGO = 5; // Кнопки, на которые будет выведен текст BTN_TEXT_0 = 6; BTN_TEXT_1 = 7; BTN_TEXT_2 = 8; var Buttons: array[0..8] of HWND; Icon: HICON; Font: HFONT; Кнопка, по своей сути, немногим отличается от главной формы приложения (это самостоятельное окно, имеющее "родителя", и обладающее своим собственным дескриптором). По этому для ее создания воспользуемся уже знакомой функцией CreateWindowEx. Посмотрим, как создается кнопка с иконкой. Buttons[0] := CreateWindowEx( WS_EX_STATICEDGE, ?Button?, nil, BS_ICON or WS_VISIBLE or WS_CHILD, 10, 15, 40, 40, Wnd, BTN_APPLICATION, hInstance, nil ); // Получаем описание нужной иконки Icon := LoadIcon( 0, IDI_APPLICATION ); // Вставляем полученную иконку в кнопку SendMessage( Buttons[0], BM_SETIMAGE, IMAGE_ICON, Icon ); Второй параметр функции CreateWindowEx говорит о том, что мы создаем именно кнопку. Определяя стиль кнопки, мы указываем, что она имеет родителя (WS_CHILD, дескриптор родителя указывается в 9-ом параметре) и будет отображать иконку (BS_ICON). С остальными параметрами мы уже знакомы. Функция LoadIcon загружает указанную иконку в наше приложение. Если первый параметр 0 (как в нашем случае), это значит, что мы работаем со стандартными системными значками (их константы указаны в модуле Windows). Загрузив иконку, назначаем ее кнопке, послав соответствующее сообщение. Остальные кнопки создаются по аналогии. Теперь поговорим о кнопках с текстом. Buttons[6] := CreateWindowEx( WS_EX_STATICEDGE, ?Button?, ?Button1?, WS_VISIBLE or WS_CHILD, 10, 70, 90, 40, Wnd, BTN_TEXT_0, hInstance, nil ); Font := GetStockObject( ANSI_VAR_FONT ); SendMessage( Buttons[6], WM_SETFONT, Font, 0 ); Buttons[7] := CreateWindowEx( WS_EX_STATICEDGE, ?Button?, ?Button2?, WS_VISIBLE or WS_CHILD, 110, 70, 90, 40, Wnd, BTN_TEXT_1, hInstance, nil ); Font := GetStockObject( ANSI_FIXED_FONT ); SendMessage( Buttons[7], WM_SETFONT, Font, 0 ); Buttons[8] := CreateWindowEx( WS_EX_STATICEDGE, ?Button?, ?Button3?, BS_DEFPUSHBUTTON or WS_VISIBLE or WS_CHILD, 210, 70, 90, 40, Wnd, BTN_TEXT_2, hInstance, nil ); Основное отличие от создания предыдущих кнопок заключается в том, что в 3-ем параметре вместо nil пишется заголовок кнопки. Обратите внимание, в описании стиля отсутствует константа BS_ICON. В принципе этого достаточно для того, чтобы отобразить надпись на кнопке (посмотрите на создание последней кнопки - Buttons[8]). Однако мы можем кое-что сделать с текстом, а именно, изменить стиль шрифта. Делается это с помощью функции GetStockObject, параметром которой и задается необходимый нам стиль. Обратим внимание на то, что последняя кнопка выглядит не совсем так, как остальные. Добиться такого результата можно, используя константу BS_DEFPUSHBUTTON при задании стиля. Теперь посмотрим, как следует обрабатывать событие, полученное от нажатия кнопки. function WindowProc( Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM ): LRESULT; stdcall; begin case Msg of WM_DESTROY: begin PostQuitMessage( 0 ); Result := 0; Exit; end; // Обработка сообщений от кнопок WM_COMMAND: case LoWord( wParam ) of BTN_APPLICATION: MessageBox( Wnd, ?IDI_APPLICATION?, ?Константа:?, MB_OK ); BTN_HAND: MessageBox( Wnd, ?IDI_HAND?, ?Константа:?, MB_OK ); BTN_QUESTION: MessageBox( Wnd, ?IDI_QUESTION?, ?Константа:?, MB_OK ); BTN_EXCLAMATION: MessageBox( Wnd, ?IDI_EXCLAMATION?, ?Константа:?, MB_OK ); BTN_ASTERISK: MessageBox( Wnd, ?IDI_ASTERISK?, ?Константа:?, MB_OK ); BTN_WINLOGO: MessageBox( Wnd, ?IDI_WINLOGO?, ?Константа:?, MB_OK ); BTN_TEXT_0: begin MessageBox( Wnd, ?Button1?, ?Кнопка:?, MB_OK ); SetFocus( Buttons[6] ); end; BTN_TEXT_1: begin MessageBox( Wnd, ?Button2?, ?Кнопка:?, MB_OK ); SetFocus( Buttons[7] ); end; BTN_TEXT_2: begin MessageBox( Wnd, ?Button3?, ?Кнопка:?, MB_OK ); SetFocus( Buttons[8] ); end; end; else Result := DefWindowProc( Wnd, Msg, wParam, lParam ); end; end; Как видим, нам нужно обработать сообщение WM_COMMAND. Параметр wParam хранит уникальный идентификатор кнопки, которая вызвала это событие. Сравниваем его с определенными в самом начале константами, идентифицируем кнопку, и выполняем связанный с ней код. И последнее на сегодня. В нашей программе кнопки с текстом должны иметь фокус. Для этого, после выполнения кода, связанного с кнопкой, вызываем процедуру SetFocus. Теперь посмотрим, как это работает. После того, как мы уберем сообщение, вызванное нажатием на одну из трех нижних кнопок, мы увидим на ней пунктирный прямоугольник, нарисованный рядом с бордюром. Это и есть результат работы процедуры SetFocus. Теперь, нажав на клавишу "пробел", мы заставим эту кнопку сработать.