Операционная система Microsoft Windows 3.1 для программиста© Александр Фролов, Григорий ФроловТом 12, М.: Диалог-МИФИ, 1993, 255 стр. 2.6. Список класса COMBOBOXВ этом разделе мы рассмотрим орган управления, создаваемый на базе предопределенного класса "combobox". Этот орган является комбинацией списка и однострочного редактора текста, поэтому для списка "combobox" используются стили, коды извещения и сообщения, аналогичные списку "listbox", а также некоторые сообщения, специфические для редактора текста класса "edit". Создание списка COMBOBOXДля того чтобы создать список класса "combobox" приложение должно вызвать функцию CreateWindow, передав в качестве первого параметра указатель на строку "combobox": hComboBox = CreateWindow("ComboBox", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_SIMPLE, 30, 30, 200, 200, hwnd, (HMENU) ID_LIST, hInst, NULL); Второй параметр функции должен быть указан как NULL. При создании списка "combobox" указываются специальные стили списка, символические имена которых имеют префикс CBS_. Остальные параметры функции CreateWindow указываются так же, как и для списка класса "listbox". Стили спискаПриведем список стилей, которые используются для создания органа управления класса "combobox". Многие из этих стилей вам уже знакомы.
Среди описанных выше стилей можно выделить три базовых. Стиль CBS_SIMPLE соответствует списку с окном редактирования (или, как его еще называют, окном выбора). Внешний вид такого списка показан на рис. 2.19.
Рис. 2. 19. Список, имеющий стиль CBS_SIMPLE Если в окне редактирования вводить строку символов (образец), то по мере ввода в списке будут появляться (и выделяться) строки, совпадающие по начальным символам с образцом. Например, если ввести букву "a", в списке окажется выделенной строка, начинающаяся с этой буквы. Если вслед за буквой "a" набрать букву "b", в списке будет выделена строка, начинающаяся с букв "ab" и т. д. Это очень удобно, например, для поиска строки по известным вам начальным буквам. Если список имеет стиль CBS_DROPDOWN, в исходном состоянии (рис. 2.20) он состоит из окна редактирования и расположенной справа от этого окна пиктограммы со стрелкой (кнопкой, предназначенной для отображения списка).
Рис. 2.20. Список, имеющий стиль CBS_DROPDOWN, в свернутом состоянии Если нажать на эту пиктограмму левой клавишей мыши, под окном редактирования появится список (рис. 2.21).
Рис. 2.21. Список, имеющий стиль CBS_DROPDOWN, в развернутом состоянии Стиль CBS_DROPDOWNLIST аналогичен стилю CBS_DROPDOWN, но окно редактирования можно использовать только для просмотра выделенной строки, а не для редактирования или ввода. Коды извещенияСписок "combobox" посылает в родительское окно сообщение WM_COMMAND. Параметр wParam этого сообщения содержит идентификатор списка. Младшее слово параметра lParam содержит идентификатор окна списка, а старшее - код извещения. Приведем список кодов извещения, поступающих от органа управления класса "combobox".
Сообщения для спискаДля управления списком "combobox" используется набор сообщений, аналогичный набору сообщений для списка "listbox" и редактора текста "edit". Функция SendMessage, посылающая сообщения списку "combobox", возвращает значение, которое зависит от выполняемой функции или коды ошибок CB_ERRSPACE (ошибка при получении дополнительной памяти), CB_ERR (затребованная операция не может быть выполнена). Если операция выполнена без ошибок, возвращается значение CB_OKAY. В файле windows.h определены сообщения, специально предназначенные для работы со списком "combobox". Символические имена этих сообщений имеют префикс CB_. Приведем список таких сообщений. CB_ADDSTRINGДобавление строки в список. Параметры: wParam = 0; lParam = (LPARAM)(LPCSTR)lpszStr; lpszStr - указатель на добавляемую строку. Возвращаемое значение: Номер строки в списке (первая строка имеет номер 0), или код ошибки. CB_DELETESTRINGУдаление строки из списка. Параметры: wParam = (WPARAM)nIndex; lParam = 0L; nIndex - номер удаляемой строки. Первая строка имеет номер 0. Возвращаемое значение: Количество строк, оставшихся в списке, или код ошибки. CB_DIRЗаполнение списка именами файлов и каталогов, расположенных в текущем каталоге, а также именами дисков. Параметры: wParam = (WPARAM)(UINT)uAttr; lParam = (LPARAM)(LPCSTR)lpszFileSpec; uAttr - атрибуты файлов; lpszFileSpec - указатель на строку, содержащую имя файла или шаблон имени файла. Возвращаемое значение: Номер последнего имени файла, добавленного в список, или код ошибки. CB_FINDSTRINGПоиск строки в списке, имеющей заданный префикс. Параметры: wParam = (WPARAM)nIndexStart; lParam = (LPARAM)(LPCSTR)lpszStr; nIndexStart - номер строки, с которой начинается поиск; lpszStr- адрес префикса строки, которую нужно найти в списке. Возвращаемое значение: Номер найденной строки, или код ошибки (если строки в списке нет). CB_GETCOUNTОпределение количества строк в списке. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: Количество строк в списке или код ошибки. CB_GETCURSELОпределение номера выделенной строки. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: Номер выделенной строки или код ошибки. CB_GETDROPPEDCONTROLRECTОпределение экранных координат видимой части списка. Используется в Windows версии 3.1 и более поздних версий. Параметры: wParam = 0; lParam = (LPARAM)(RECT FAR *) lprc ;lprc - указатель на структуру RECT, в которую будут записаны искомые координаты. Возвращаемое значение: Всегда возвращается CB_OKAY. CB_GETDROPPEDSTATEС помощью этого сообщения можно определить, находится список в видимом или невидимом состоянии. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: TRUE, если список виден, FALSE - если нет. CB_GETEDITSELОпределение положения первого и последнего символа в выделенном фрагменте текста. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: Двойное слово. Младшее слово содержит положение первого символа в выделенном фрагменте, старшее - положение символа, следующего за выделенным фрагментом текста CB_GETEXTENDUIС помощью этого сообщения можно определить, использует ли список расширенный интерфейс пользователя. Это сообщение используется в Windows версии 3.1 и более поздних версий.При использовании расширенного интерфейса щелчок в окне редактора текста для стиля CBS_DROPDOWMLIST приводит к отображению списка. Список также отображается, когда пользователь нажимает клавишу перемещения курсора вниз <Down>. Если список находится в невидимом состоянии, свертка окна редактирования не выполняется. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: TRUE, если расширенный интерфейс пользователя используется, FALSE - если нет. СB_GETITEMDATAПолучение 32-битового значения, соответствующего заданной строке. Параметры: wParam = (WPARAM)nIndex; lParam = 0L; nIndex - номер строки, для которой нужно получить значение. Возвращаемое значение: Двойное слово, содержащее искомое значение, или код ошибки. СB_GETITEMHEIGHTОпределение высоты заданной строки в списке, который рисуется родительским окном и имеет переменную высоту элементов. Это сообщение используется в Windows версии 3.1 и более поздних версий. Параметры: wParam = (WPARAM)nIndex; lParam = 0L; nIndex - номер строки, для которой нужно получить значение. Возвращаемое значение: Высота строки в пикселях или код ошибки. CB_GETLBTEXTКопирование текста, соответствующего заданной строке, в буфер. Параметры: wParam = (WPARAM)nIndex; lParam = (LPARAM)(int FAR *)lpszBuffer; nIndex - номер строки. lpszBuffer - адрес буфера. Возвращаемое значение: Длина строки в байтах (с учетом двоичного нуля, закрывающего строку), или код ошибки. CB_GETLBTEXTLENОпределение длины строки, содержащейся в списке. Параметры: wParam = (WPARAM)nIndex; lParam = 0L; nIndex - номер строки. Возвращаемое значение: Длина строки в байтах (с учетом двоичного нуля, закрывающего строку), или код ошибки. CB_INSERTSTRINGВставка элемента в заданную позицию списка. На расположение строки не влияет стиль LBS_SORT. Параметры: wParam = (WPARAM)nIndex; lParam = (LPARAM)(int FAR *)lpszBuffer; nIndex - номер позиции, в которую будет вставлена строка.lpszBuffer - адрес буфера. Возвращаемое значение: Номер позиции, в которую вставлена строка, или код ошибки. CB_LIMITTEXTОпределение максимального количества символов, которое можно ввести в окно редактирования. Параметры: wParam = (WPARAM)cCmax; lParam = 0L; cCMax - размер текста. Возвращаемое значение: не используется CB_RESETCONTENTУдаление всех строк из списка. Параметры: wParam = 0; lParam = 0L; Возвращаемое значение: не используется. CB_SELECTSTRINGПоиск строки в списке, которая начинается с символов, соответствующих образцу. Найденная строка становится выбранной. Параметры: wParam = (WPARAM)nIndexStart; lParam = (LPARAM)(int FAR *)lpszBuffer; nIndexStart - номер строки, с которой начинается поиск.lpszBuffer - адрес буфера, содержащего образец. Возвращаемое значение: Номер найденной строки или код ошибки. CB_SETCURSELВыбор указанной строки. Ранее выделенная строка становится невыделенной. Если данная строка находится вне окна отображения, список сворачивается таким образом, чтобы строка стала видимой. Параметры: wParam = (WPARAM)nIndex; lParam = 0L; nIndex - номер строки. Если указать -1, выделение всех строк будет отменено. При этом функция SendMessage вернет значение CB_ERR, что в данном случае не говорит об ошибке. Возвращаемое значение: Код ошибки (если значение nIndex не равно -1). CB_SETEDITSELВыделение заданных символов в окне редактирования. Параметры: wParam = (WPARAM)(UINT)fScroll; lParam = MAKELPARAM(ichStart, ichEnd); fScroll - если этот параметр равен 1, текстовый курсор сворачивается, если 0 - нет.ichStart - начальная позиция. ichEnd - конечная позиция. Если начальная позиция равна 0, а конечная -1, выбирается весь текст. Если начальная позиция равна -1, выделение фрагмента (если оно было) исчезает. Возвращаемое значение: TRUE, если сообщение посылается операция выполнена без ошибок или код ошибки. CB_SETEXTENDEDUIУстановка режима использования расширенного интерфейса пользователя. Это сообщение используется в Windows версии 3.1 и более поздних версий. Параметры: wParam = (WPARAM)(BOOL)fExtended; lParam = 0L; fExtended - TRUE для установки режима, FALSE - для сброса. Возвращаемое значение: CB_OKAY, если сообщение посылается операция выполнена без ошибок или код ошибки CB_ERR. CB_SETITEMDATAУстановка значения двойного слова, связанного с указанным элементом списка. Параметры: wParam = (WPARAM)nIndex; lParam = (LPARAM)dwData; nIndex - номер строки. dwData - значение двойного слова. Возвращаемое значение: Код ошибки. CB_SETITEMHEIGHTУстановка высоты элемента в списке, который рисует родительское окно и имеет переменную высоту элементов. Это сообщение используется в Windows версии 3.1 и более поздних версий. Параметры: wParam = (WPARAM)nIndex; lParam = MAKELPARAM(cyItem, 0); nIndex - номер строки. Если список не имеет стиль LBS_OWNERDRAWVARIABLE, значение этого параметра должно быть равно 0.cyItem - высота элемента в пикселах. Возвращаемое значение: Код ошибки. CB_SHOWDROPDOWNПереключение списка в отображаемое или неотображаемое состояние. Параметры: wParam = (WPARAM)(BOOL)fExtended; lParam = 0L; fExtended - TRUE для отображения списка, FALSE - для переключения списка в неотображаемое состояние. Возвращаемое значение: всегда не равно 0 Приложение COMBOДля иллюстрации методов работы со списком "combobox" приведем исходные тексты приложения COMBO (листинг 2.30). Это приложение создает в своем главном окне (рис. 2.22) список, предназначенный для выбора файлов, каталогов и дисков (аналогично предыдущему приложению LISTDIR).
Рис. 2.22. Главное окно приложения COMBO В некоторых случаях орган управления "combobox" удобнее, чем "listbox". Например, если вам надо выбрать имя файла из каталога, содержащего сотни файлов, простой просмотр списка может отнять много времени. Типичный пример - поиск файлов win.ini и system.ini в каталоге операционной системы Windows. В нашем приложении COMBO создается список, имеющий стиль CBS_SIMPLE. Этот стиль позволяет упростить поиск, если вы знаете хотя бы несколько первых букв имени файла. Наберите начало имени в окне редактирования, и имя нужного файла окажется перед вашими глазами (рис. 2.22). Для экономии места в книге мы удалили все комментарии из исходного текста, так как мы уже разбирали аналогичное приложение LISTDIR. Исходные тексты с комментариями вы можете найти на дискете, которая прилагается к книге. Листинг 2.30. Файл combo\combo.cpp // ---------------------------------------- // Использование органа управления // класса "combobox" для просмотра // содержимого каталога // ---------------------------------------- #define STRICT #include <windows.h> #include <mem.h> #include <dir.h> #define ID_LIST 1 #define ID_BUTTON 2 BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); char const szClassName[] = "ComboAppClass"; char const szWindowTitle[] = "Выбор файла"; HINSTANCE hInst; // ===================================== // Функция WinMain // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения if(!InitApp(hInstance)) return FALSE; hInst = hInstance; hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем расположение и размеры CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, // CW_USEDEFAULT, // 0, // идентификатор родительского окна 0, // идентификатор меню hInstance, // идентификатор приложения NULL); // указатель на дополнительные // параметры if(!hwnd) return FALSE; ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } // ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна memset(&wc, 0, sizeof(wc)); wc.style = 0; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = (LPSTR)szClassName; aWndClass = RegisterClass(&wc); return (aWndClass != 0); } // ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HWND hComboBox; static HWND hButton; switch (msg) { case WM_CREATE: { hComboBox = CreateWindow("ComboBox", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_SIMPLE, 30, 30, 200, 200, hwnd, (HMENU) ID_LIST, hInst, NULL); SendMessage(hComboBox, CB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*"); hButton = CreateWindow("button", "OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 250, 30, 50, 20, hwnd, (HMENU) ID_BUTTON, hInst, NULL); return 0; } case WM_SETFOCUS: { SetFocus(hComboBox); return 0; } case WM_COMMAND: { if(wParam == ID_LIST) { if(HIWORD(lParam) == (unsigned)CBN_ERRSPACE) { MessageBox(hwnd, "Мало памяти", szWindowTitle, MB_OK); } else if(HIWORD(lParam) == CBN_DBLCLK) { SendMessage(hwnd, WM_COMMAND, ID_BUTTON, 0L); return 0; } else if(HIWORD(lParam) == CBN_SELCHANGE) { int uSelectedItem, nSize; char Buffer[256]; HDC hdc; uSelectedItem = (int)SendMessage(hComboBox, CB_GETCURSEL, 0, 0L); if(uSelectedItem != CB_ERR) { // Получаем строку SendMessage(hComboBox, CB_GETLBTEXT, uSelectedItem, (LPARAM)Buffer); hdc = GetDC(hwnd); nSize = lstrlen(Buffer); TextOut(hdc, 250, 60, (LPSTR)" ", 25); TextOut(hdc, 250, 60, (LPSTR)Buffer, nSize); ReleaseDC(hwnd, hdc); } } } else if(wParam == ID_BUTTON) { int uSelectedItem; char Buffer[256]; uSelectedItem = (int)SendMessage(hComboBox, CB_GETCURSEL, 0, 0L); if(uSelectedItem != LB_ERR) { SendMessage(hComboBox, CB_GETLBTEXT, uSelectedItem, (LPARAM)Buffer); if(Buffer[0] == '[') { Buffer[lstrlen(Buffer) - 1] = '\0'; if(chdir(&Buffer[1]) != 0) { Buffer[3] = '\0'; lstrcat(Buffer, ":\\"); if(chdir(&Buffer[2]) == 0) { AnsiLowerBuff(&Buffer[2], 1); setdisk(Buffer[2] - 'a'); } } SendMessage(hComboBox, CB_RESETCONTENT, 0, 0L); SendMessage(hComboBox, CB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*"); } else { MessageBox(hwnd, Buffer, szWindowTitle, MB_OK); } } } return 0; } case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 30, 10, "Выберите файл, каталог или диск", 31); EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: { PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } Файл определения модуля приложения COMBO приведен в листинге 2.31. Листинг 2.31. Файл combo\combo.def ; ============================= ; Файл определения модуля ; ============================= NAME COMBO DESCRIPTION 'Приложение COMBO, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 5120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |