// ===================================== // Функция WinMain // ===================================== #pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения
// Когда главное окно приложения получает // фокус ввода, отдаем фокус списку case WM_SETFOCUS: { SetFocus(hListBox); return 0; }
case WM_COMMAND: { // Обработка извещения списка об ошибке if(wParam == ID_LIST) { // Преобразуем к типу unsigned, так как // константа LBN_ERRSPACE определена как // отрицательное число if(HIWORD(lParam) == (unsigned)LBN_ERRSPACE) { MessageBox(hwnd, "Мало памяти", szWindowTitle, MB_OK); }
// Если пользователь сделал двойной щелчок // по строке списка, выводим эту строку // на экран else if(HIWORD(lParam) == LBN_DBLCLK) { int uSelectedItem; char Buffer[256];
// Если в списке есть выделенная строка, // выводим ее на экран if(uSelectedItem != LB_ERR) { // Получаем выделенную строку SendMessage(hListBox, LB_GETTEXT, uSelectedItem, (LPARAM)Buffer);
// Выводим ее на экран MessageBox(hwnd, (LPSTR)Buffer, szWindowTitle, MB_OK); } }
// Если пользователь изменил выделенную // строку, выводим в окно новую // выделенную строку else if(HIWORD(lParam) == LBN_SELCHANGE) { int uSelectedItem, nSize; char Buffer[256]; HDC hdc;
// Определяем номер новой выделенной строки uSelectedItem = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);
// Сообщение от кнопки else if(wParam == ID_BUTTON) { int uSelectedItem; char Buffer[256];
// Определяем номер выделенной строки, // получаем текст строки и выводим // этот текст в окно uSelectedItem = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);
// Это сообщение поступает от списка, если он // имеет фокус ввода и пользователь работает // с клавиатурой case WM_VKEYTOITEM: { // Если пользователь нажал клавишу <Enter> , // посылаем в окно сообщение WM_COMMAND с // параметром wParam, равным идентификатору // кнопки if(wParam == VK_RETURN) { SendMessage(hwnd, WM_COMMAND, ID_BUTTON, 0L); } return -1; }
case WM_PAINT: { HDC hdc; PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 30, 10, "Выберите цвет и нажмите кнопку 'OK'", 35);
Для того чтобы родительское окно могло получать от списка клавиатурные сообщения, дополнительно к стилю LBS_STANDARD указан стиль LBS_WANTKEYBOARDINPUT.
После создания списка его надо заполнить строками. Перед началом этой процедуры функция главного окна приложения отменяет режим перерисовки списка после добавления в него очередной строки, посылая списку сообщение WM_SETREDRAW со значением параметр wParam, равным FALSE:
SendMessage(hListBox, WM_SETREDRAW, FALSE, 0L);
Вслед за этим функция окна добавляет в список несколько строк, посылая списку несколько раз сообщение LB_ADDSTRING:
Далее обработчик сообщения WM_CREATE создает кнопку, которая будет использована для выбора из списка выделенной строки.
Так как для работы со списком используется клавиатура, получив сообщение WM_SETFOCUS, функция главного окна приложения отдает фокус ввода списку:
case WM_SETFOCUS: { SetFocus(hListBox); return 0; }
Обработчик сообщения WM_COMMAND получает управление, когда от списка приходит извещение о событии, или когда пользователь нажимает кнопку.
Если для работы списка не хватает памяти, он посылает извещение LBN_ERRSPACE. В ответ на это приложение выводит на экран диалоговую панель с сообщением об ошибке.
Если пользователь сделал двойной щелчок по строке списка, приходит извещение LBN_DBLCLK.
Обработчик этого извещения определяет номер выделенной строки (т. е. строки по которой был сделан двойной щелчок), посылая списку сообщение LB_GETCURSEL:
Номер строки передается через параметр wParam, адрес буфера указывается через параметр lParam.
Далее полученная строка выводится на экран при помощи функции MessageBox.
Обработчик извещения LBN_SELCHANGE получает управление, когда пользователь изменяет выделенную строку (т. е. выделяет другую строку) списка. В этом случае обработчик извещения посылает окну сообщение LB_GETCURSEL для определения номера новой выделенной строки. Вслед за этим он переписывает эту строку в буфер, посылая списку сообщение LB_GETTEXT:
Полученная строка отображается в главном окне приложения при помощи функции TextOut:
TextOut(hdc, 250, 60, (LPSTR)Buffer, nSize);
Действия, выполняемые обработчиком сообщения WM_COMMAND при получении сообщения от кнопки, полностью аналогичны действиям при обработке извещения LBN_DBLCLK.
В этом случае обработчик сообщения определяет номер выделенной строки, переписывает эту строку в буфер и выводит ее на экран.
Так как при создании списка был указан класс LBS_WANTKEYBOARDINPUT, список посылает в родительское окно сообщение WM_VKEYTOITEM (если бы мы создавали список без стиля LBS_HASSTRINGS, вместо этого сообщения в родительское окно посылалось бы сообщение WM_CHARTOITEM). Параметр wParam для этого сообщения содержит значение виртуального кода нажатой клавиши. Наше приложение пользуется этим, отслеживая выбор строки клавишей <Enter> (клавише <Enter> соответствует виртуальный код VK_RETURN):
Обработчик сообщения WM_VKEYTOITEM посылает функции главного окна сообщение WM_COMMAND, имитируя выбор строки кнопкой "OK".
Обработчик возвращает значение -1, позволяя списку выполнить обработку кода клавиши, назначенную по умолчанию. Вместо этого можно было бы вернуть значение -2. В таком случае список игнорирует сообщения клавиатуры, а все изменения в списке должны выполняться родительским окном. Если вернуть нулевое или положительное значение, список выделит выбранную строку и выполнит обработку кода клавиши по умолчанию.
Файл определения модуля для приложения LISTBOX приведен в листинге 2.27.