Списки обыкновенные. Перехват нажатия клавиш клавиатуры.
Представленный ниже пример содержит в себе несколько нюансов. Придется нам остановиться на нем подробнее.Сама задача управление таким сложным элементом, как списки, тянет за собой несколько других задач: управление элементами в окне, обработка нажатия клавиш.
Конечно, мы уже понимаем, как создавать элементы. Для этого используем функцию API CreateWindowExW. Мы понимаем, перехватывать сигналы от этих элементов. Но возникает вопрос, а как управлять этими элементами. Ну в частности как добавить или удалить элемент списка. Для этого существует замечательная функция API SenMessageW. Для каждого из стандартных элементов имеется набор команд - кодов команд. Из опыта мы знаем, что для управления элементами окна с помощью клавиш необходима возможность перемещения фокуса ввода от одного элемента к другому. Обычно для этого используют клавишу TAB. Но вот беда, мы рассматриваем простые окна, а не диалоговые. События нажатия клавиш им не пересылаются. Чтобы обойти эту проблему нам придется несколько модернизировать цикл обработки сообщений.
#include <Windows.h>
LRESULT CALLBACK winproc( HWND, UINT, WPARAM, LPARAM);
WNDCLASSEXW ws; //струкутра для регистрации класса окон
wchar_t * wn = L"class1"; //имя класса
MSG msg; //для сообщения
HWND hwnd; //для дескриптора окна
HWND hb[5];
HINSTANCE h;
int i;
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
h=hInstance;
ws.cbSize = sizeof(WNDCLASSEXW);
ws.cbClsExtra = 0;
ws.cbWndExtra = 0;
ws.hIcon = LoadIcon( NULL, IDI_APPLICATION );
ws.hCursor = LoadCursor( NULL, IDC_ARROW );
ws.hbrBackground = CreateSolidBrush(RGB(0, 80, 80));
ws.hIcon = NULL;
ws.hInstance = hInstance;
ws.lpszClassName = wn;
ws.lpszMenuName = NULL;
ws.lpfnWndProc = (WNDPROC)winproc;
ws.style = CS_VREDRAW|CS_HREDRAW;
//зарегистрировать класс окна
if(RegisterClassExW(&ws)==0){
MessageBoxExW(0,L"Ошибка регистрации!",L"Сообщение", 0, 0); return 0;
};
//создать окно
hwnd= CreateWindowExW(0, //расширенный стиль
wn, //имя класса
L"Окно в 64-битово системе!", //заголовок окна
WS_OVERLAPPEDWINDOW, //стиль окна
10, //x
10, //y
600, //ширина
400, //высота
NULL, //дескриптор родительского окна
NULL, //дескриптор меню
hInstance, //дескриптор приложения
NULL); //параметр приходящий на функцию окна вместе с сообщением WM_CREATE
//сделать окно видимым
ShowWindow( hwnd, nCmdShow );
//обновить содержимое
UpdateWindow(hwnd );
//цикл обработки сообщений
while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
if(msg.message==WM_KEYDOWN){
winproc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
//выход из программы
return (int)msg.wParam;
}
//функция окна
LRESULT CALLBACK winproc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
wchar_t s[25]; int j, *k;
switch ( uMsg ) {
case WM_KEYDOWN:
//обработка нажатия клавиши tab
if(wParam==9){
if(i==4)i=0;else i++;
SetFocus(hb[i]);
}
break;
case WM_CREATE:
//создание элементов управления
hb[0]=CreateWindowExW(0,L"button", L"Выход",
WS_CHILD |WS_TABSTOP| WS_VISIBLE | BS_PUSHBUTTON | BS_NOTIFY, 500, 10, 80, 30, hWnd, 0, h, NULL);
hb[1]=CreateWindowExW(0,L"listbox", L"",
WS_CHILD |WS_TABSTOP| WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY, 10, 10, 150, 200, hWnd, 0, h, NULL);
SendMessageW(hb[1], LB_SETCOLUMNWIDTH, 25, 0);//установить ширину колонки списка
hb[2]=CreateWindowExW(0,L"Edit", L"",
WS_CHILD | WS_VISIBLE |WS_TABSTOP | ES_AUTOHSCROLL | WS_BORDER,
180, 10, 180, 20, hWnd, 0, h, NULL);
SendMessageW(hb[2], EM_SETLIMITTEXT, 20, 0);//длина вводимой строки
hb[3]=CreateWindowExW(0,L"button", L"Добавить",
WS_CHILD |WS_TABSTOP| WS_VISIBLE | BS_PUSHBUTTON | BS_NOTIFY, 180, 40, 80, 30, hWnd, 0, h, NULL);
hb[4]=CreateWindowExW(0,L"button", L"Удалить",
WS_CHILD |WS_TABSTOP| WS_VISIBLE | BS_PUSHBUTTON | BS_NOTIFY, 280, 40, 80, 30, hWnd, 0, h, NULL);
i=1; SetFocus(hb[i]);
break;
case WM_COMMAND:
if(lParam==(int)hb[0]){//кнопка выхода
if(HIWORD(wParam)==BN_CLICKED){
DestroyWindow(hWnd);//закрыть приложение
}
}
if(lParam==(int)hb[3]){
if(HIWORD(wParam)==BN_CLICKED){//кнопка добавления строки в список
k = (int*)s; *k=24;//в начале буфера - его длина
j = SendMessageW(hb[2], EM_GETLINE, 0, (LPARAM)s);//получить строку
s[j]=L'\ 0'
SendMessageW(hb[1], LB_ADDSTRING, 0, (LPARAM)s);
}
}
if(lParam==(int)hb[4]){//кнопка удаления строки из списка
if(HIWORD(wParam)==BN_CLICKED){
j=SendMessageW(hb[1],LB_GETCURSEL,0,0);
if(j!=LB_ERR)SendMessageW(hb[1],LB_DELETESTRING,j,0);
}
}
break;
case WM_SHOWWINDOW:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
};
В первую очередь следует обратить внимание на то, как была решена проблема обработки нажания клавиш клавиатуры. Это общий подход, который может быть использован для работы с любыми клавишами. Сам же механизм перехода фокуса ввода от одного элемента к другому осуществляется при помощи функции API SetFocus и массива hb, который по сути индексирует элементы окна.

Очень важную роль программе играет функция API SendMessageW. Первым параметром функции является дескриптор окна, куда посылается сообщение. Поскольку все наши элементы в сущности это окна, то мы используем функцию для посылки туда сообщения. Следущий параметр - код сообщения. Для каждого стандартного элемента есть свои наборы кодов. Соответственно последние два параметра интерпретируются в зависимости от этого кода.

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

Ну вот пока все. Наслаждайтесь программированием.

 Назад       Заметки       Сайт       Страница-портал       Журнал
(c) Copyright Владислава Юрьевич Пирогов