API и FreeBasic. (дочерние окна-ListBox)

ListBox - это контрол, способный создавать список строк. Имеет в себе возможность автосортировки, заполнение именами файлов и дисков, а так же присутствует поиск.  В его кухне что-то около 40  возможных сообщений и 15 стилей,  с помощью которых и ведется создание и модернизация контрола.

Создается контрол как обычно функцией CreateWindow или CreateWindowEx. Стили указываются в зависимости от задачи:

  • LBS_DISABLENOSCROLL - Показывает заблокированную вертикальную линейку прокрутки в окне со списком, когда поле окна не содержит достаточно элементов для прокрутки. Если Вы не определяете этот стиль, линейка прокрутки скрыта, когда окно со списком не содержит достаточно элементов.
  • LBS_EXTENDEDSEL - Позволяет многочисленным элементам быть выбранными, при помощи использования клавиши SHIFT и мыши или специальной комбинации клавиш.
  • LBS_HASSTRINGS - Определяет, что окно со списком содержит элементы, состоящие из строк. Окно со списком сохраняет память и адреса строк, так что прикладная программа может использовать сообщение LB_GETTEXT, чтобы восстановить текст для отдельного элемента. По умолчанию, все окна со списком за исключением окон со списком предоставленных владельцем имеют этот стиль. Вы можете создать предоставляемое владельцем окно со списком с ним или без этого стиля.
  • LBS_MULTICOLUMN - Определяет многостолбцовое окно со списком, которое прокручивается горизонтально. Сообщение LB_SETCOLUMNWIDTH устанавливает ширину столбцов.
  • LBS_MULTIPLESEL - Включает или выключает выбор последовательности символов каждый раз, когда пользователь одним или двойным щелчком мыши активизирует строку символов в окне со списком. Пользователь может выбрать любое число строк.
  • LBS_NODATA - Определяет "отсутствие данных" в окне со списком. Этот стиль определяется тогда, когда число элементов в окне со списком может превысить одну тысячу. Окно со списком с "отсутствующими данными" должно иметь также стиль LBS_OWNERDRAWFIXED, но не должно иметь стилей LBS_SORT или LBS_HASSTRINGS. Окно со списком с "отсутствующими данными" имеет сходство с окном со списком предоставляемым владельцем за исключением того, что оно не содержит ни строковых или растровых данных для элемента. Команды "добавить", "вставить" или "удалить" элемент всегда игнорируют любые передаваемые элементы данных; запрос на поиск строки внутри окна всегда терпит неудачу. Windows посылает сообщение WM_DRAWITEM окну владельцу, когда элемент должен быть прорисован. ЭлементID (itemID) член структуры DRAWITEMSTRUCT, переданный с сообщением WM_DRAWITEM, определяет номер строки элемента, который будет прорисован. Окно списка с "отсутствующими данными" не посылает сообщение WM_DELETEITEM.
  • LBS_NOINTEGRALHEIGHT - Определяет, что размер окна со списком соответствует размеру, определенному прикладной программой, когда она создавала окно со списком. Обычно, Windows устанавливает величину окна со списком так, чтобы оно не отображало элементы частично.
  • LBS_NOREDRAW - Определяет, что вид окна со списком не модифицируется, когда производятся изменения. Вы можете в любое время изменить этот стиль, посылая сообщение WM_SETREDRAW.
  • LBS_NOSEL - Определяет, что окно со списком содержит элементы, которые могут просматриваться, но не выбираться.
  • LBS_NOTIFY - Сообщает родительскому окну о входящем сообщении всякий раз, когда пользователь щелкает мышью или дважды щелкает по строке в окне списка.
  • LBS_OWNERDRAWFIXED - Определяет, что владелец окна со списком ответственен за прорисовку его содержания и что элементы в окне со списком появляются одинаковой высоты. Окно владельца принимает сообщение WM_MEASUREITEM, когда окно со списком создано, а сообщение WM_DRAWITEM, когда внешний вид окна изменился.
  • LBS_OWNERDRAWVARIABLE - Определяет, что владелец окна со списком ответственен за прорисовку его содержания и что элементы в окне со списком появляются переменными по высоте. Окно владельца принимает сообщение WM_MEASUREITEM для каждого элемента в окне со списком, когда оно создано, а сообщение WM_DRAWITEM, когда внешний вид окна изменился.
  • LBS_SORT - Сортирует строки в окне со списком по алфавиту.
  • LBS_STANDARD - Сортирует строки в окне со списком в алфавитном порядке. Родительское окно принимает входящее сообщение всякий раз, когда пользователь щелкает мышью или дважды щелкает по строке. Окно со списком имеет, рамку со всех сторон.
  • LBS_USETABSTOPS - Дает возможность окну списка распознавать и развернуть символы в виде таблицы при прорисовке его строк. По умолчанию таблица занимает 32 единицы измерения диалогового окна. Единица измерения диалогового окна - горизонтальное или вертикальное расстояние. Одна горизонтальная единица диалогового окна равна четвертой части текущей единицы измерения габаритов диалогового окна. Windows вычисляет эти единицы измерения, основанные на высоте и ширине шрифта существующей системы. Функция GetDialogBaseUnits возвращает значение текущей базовой единицы измерения диалогового окна в пикселях.
  • LBS_WANTKEYBOARDINPUT - Определяет, что владелец окна списка принимает сообщения WM_VKEYTOITEM всякий раз, когда пользователь нажимает клавишу, а окно со списком имеет фокус ввода. Это дает возможность прикладной программе выполнить специальную обработку при вводе с клавиатуры.

А это некоторые сообщения, которые можно отправлять контролу(все можно посмотреть ЗДЕСЬ):

  • LB_ADDSTRING - Добавление строки в список.
  • LB_DELETESTRING - Удаление строки из списка.
  • LB_DIR - Заполнение списка именами файлов и каталогов, расположенных в текущем каталоге, а также именами дисков.
  • LB_FINDSTRING - Поиск строки в списке, имеющей заданный префикс. Будет найдена строка, начальная часть которой совпадает с текстовой строкой, определенной в качестве префикса.
  • LB_FINDSTRINGEXACT - Поиск строки в списке.Не чувствителен к регистру.
  • LB_GETCARETINDEX - Определение номера строки, имеющей фокус ввода. Это сообщение используется в Windows версии 3.1 и более поздних версий.
  • LB_GETCOUNT - Определение количества строк в списке.
  • LB_GETCURSEL - Определение номера выделенной строки.
  • LB_GETHORIZONTALEXTENT - Определение ширины сворачиваемой области списка, имеющего горизонтальную полосу просмотра.
  • LB_GETITEMDATA - Получение 32-битового значения, соответствующего заданной строке. Напомним, что каждому элементу списка ставится в соответствие некоторое число, занчение которого можно определить с помощью этого сообщения.
  • LB_GETITEMHEIGHT - Определение высоты заданной строки в списке, который рисуется родительским окном и имеет переменную высоту элементов. Это сообщение используется в Windows версии 3.1 и более поздних версий.
  • LB_GETITEMRECT - Определение координат внутренней области окна, соответствующей заданной строке. 
  • LB_GETSEL - С помощью этого сообщения можно определить, выбрана ли указанная строка списка.
  • LB_GETSELCOUNT - С помощью этого сообщения можно определить количество выбранных строк. 
  • LB_GETSELITEMS - Заполнение буфера идентификаторами выбранных строк для списка, в котором можно выбирать несколько строк сразу.
  • LB_GETTEXT - Копирование текста, соответствующего заданной строке, в буфер. Если список не содержит строк (определен без стиля LBS_HASSTRING), в буфер копируется двойное слово, соответствующее указанному элементу списка.
  • LB_GETTEXTLEN - Определение длины строки, содержащейся в списке.
  • LB_GETTPOINDEX - Определение номера первой отображаемой строки. 
  • LB_INSERTSTRING - Вставка элемента в заданную позицию списка. На расположение строки не влияет стиль LBS_SORT.
  • LB_RESETCONTENT - Удаление всех строк из списка.
  • LB_SELECTSTRING - Поиск строки в списке, которая начинается с символов, соответствующих образцу. Найденная строка становится выбранной.
  • LB_SELITEMRANGE - Выделение одной или нескольких расположенных рядом строк.
  • LB_SETCARETINDEX - Передача фокуса ввода указанной строке. Если данная строка находится вне окна отображения, список сворачивается таким образом, чтобы строка стала видимой. Это сообщение используется в Windows версии 3.1 и более поздних версий.
  • LB_SETCOLUMNWIDTH - Установка ширины колонки в многоколоночном списке.
  • LB_SETCURSEL - Выбор указанной строки. Ранее выделенная строка становится невыделенной. Если данная строка находится вне окна отображения, список сворачивается таким образом, чтобы строка стала видимой.
  • LB_SETHORIZONTALEXTENT - Установка ширины, на которую может быть свернут список, имеющий стиль WS_HSCROLL.
  • LB_SETITEMDATA - Установка значения двойного слова, связанного с указанным элементом списка.
  • LB_SETITEMHEIGHT - Установка высоты элемента в списке, который рисует родительское окно и имеет переменную высоту элементов. Это сообщение используется в Windows версии 3.1 и более поздних версий.
  • LB_SETSEL - Установка высоты элемента в списке, который рисует родительское окно и имеет переменную высоту элементов. Это сообщение используется в Windows версии 3.1 и более поздних версий.
  • LB_SETTABSTOPS - Установка позиции табуляции в списке.
  • LB_SETTOPINDEX - Свертка списка до тех пор, пока указанная строка не станет видимой.

Сообщения от контрола приходят в оконную процедуру родителя. Контрол посылает ему сообщение WM_COMMAND. При этом в параметре LPARAM окажется хендл контрола. WPARAM делится на две половинки:

В старшей половинке, результат которой можно получить с помощью макроса HIWORD, лежит один из кодов извещения:

  • LBN_DBLCLK - Двойной щелчок левой клавишей мыши по строке списка
  • LBN_ERRSPACE - Ошибка при попытке заказать дополнительную память
  • LBN_KILLFOCUS - Список теряет фокус ввода
  • LBN_SELCANCEL - Пользователь отменил выбор в списке. Это извещение используется в Windows версии 3.1 и более поздних версий
  • LBN_SELCHANGE - Изменился номер выбранной строки (т. е. пользователь выбрал другую строку)
  • LBN_SETFOCUS - Список получает фокус ввода

В младшей половинке будет номер пункта списка. Ее можно получить с помощью макроса LOWORD.

Ниже в примере создан список из нескольких пунктов. Если перемещаться по пунктам, то в заголовке окна-родителя можно увидеть содержание пунктов. Если нажать на какой нибудь пункт двойным челчком, то текст пункта будет изменен. А если нажать на кнопку , то список выведет все ваши диски в системе.
Последнее дистигается сообщением LB_DIR .При том в параметре WPARAM передается соответствующая константа, определяющая вывод значений:

  • DDL_ARCHIVE - Файлы, для которых в байте атрибутов установлен бит архивирования
  • DDL_DIRECTORY - Каталоги
  • DDL_DRIVES - Дисковые устройства
  • DDL_EXCLUSIVE - В список не будут включены имена обычных файлов
  • DDL_HIDDEN - Скрытые файлы
  • DDL_READONLY - Только читаемые файлы
  • DDL_READWRITE - Файлы, над которыми можно выполнять операции чтения/записи, не имеющие дополнительных атрибутов
  • DDL_SYSTEM - Системные файлы

А в параметре LPARAM задается указатель на строковую переменную, в которой указывается путь для вывода и следом без пробела и каких либо разделителей маска для имени. В нашем примере указывается только путь (корневая директория) .  

Пример:

#INCLUDE "windows.bi"
#INCLUDE "win/commctrl.bi"
InitCommonControls()
Dim msg As MSG
Dim As WNDCLASSEX wc
Dim As String NameClass="MyClass"
Dim As HINSTANCE Hinst=GetModuleHandle(0)
Dim Shared As HWND hwndM

Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Static As HWND Listbox,but
    Select Case msg
        Case WM_CREATE
            Listbox=CreateWindowEx( WS_EX_CLIENTEDGE,_
            WC_LISTBOX,_
            "ListBox",_
            WS_VISIBLE Or WS_CHILD Or LBS_SORT Or LBS_NOTIFY,_
            10,10,200,200,hwnd,Cast(HMENU,1),0,0)
            For a As Integer=0 To 9
                Var stringLB=Str(Rnd*100)
                SendMessage(Listbox, LB_ADDSTRING ,a,Cast(LPARAM,Strptr(stringLB)))
            Next
            but=CreateWindowEx(0,"Button","Имена файлов",_
            WS_VISIBLE Or WS_CHILD,45,230,130,20,hwnd,Cast(HMENU,2),0,0)
        Case WM_COMMAND
            If Loword(WPARAM)=1 Then
                Dim As String*32 st
                Dim As Integer i=SendMessage(Listbox,LB_GETCURSEL ,0 ,0)
                SendMessage(Listbox,LB_GETTEXT,i,Cast(LPARAM,@st))
                If Hiword(WPARAM)=LBN_DBLCLK Then
                    SendMessage(Listbox,LB_INSERTSTRING ,i ,Cast(LPARAM,@"Заменен"))
                    SendMessage(Listbox,LB_DELETESTRING ,i+1 ,0)
                Elseif Hiword(WPARAM)=LBN_SELCHANGE Then
                    If i<> LB_ERR Then
                        SendMessage(hwndM,WM_SETTEXT,0,Cast(LPARAM,@st))
                    Endif
                Endif
            Elseif Loword(WPARAM)=2 Then
                SendMessage(Listbox,LB_RESETCONTENT,0,0)
                SendMessage(Listbox,LB_DIR,DDL_DRIVES,Cast(LPARAM,@".."))
            Endif
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function

With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With

If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif

hwndM=CreateWindowEx(0,NameClass,"ListBox",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,250,300,0,0,Hinst,0)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend


Вот что примерно должно быть:

listboxcontrol.png

Как в дополнение: в примере для вставки пунктов используется вызов функции SendMessage с сообщением LB_ADDSTRING. При такой вставке, используя в стилях LBS_SORT, идет автосортировка. Если использовать для вставки сообщение LB_INSERTSTRING сортировки не будет! Для возможности получать сообщения двойного клика мыши, необходим стиль LBS_NOTIFY, что мы и указали. У контрола нет сообщения для изменения текста. Поэтому это достигается вставкой нового пункта и удалением старого.

Вот собственно и все, всего доброго!

содержание | назад | вперед