(Продолжение, начало см. МК № 1 (172))
Для навигации в списках, имеющих значительное количество элементов и заполненных символами кириллицы, можно предложить обработку массивов. Упрощенный вариант кода предложен далее, а результат см. на рис. 1. Думаю, уже по рисунку видать, что на форму были помещены ЭУ ListBox и TextBox.
Private Sub UserForm_Initialize() ' Заполняем список With ListBox1 .AddItem "Фролов В.И." .AddItem "Сидоров В.А." .AddItem "Сидоркин И.Б." .AddItem "Петров Е.З." .AddItem "Сидорович Б.Д." .AddItem "Арбузов П.П." .AddItem "Сахаров Ю.Ю." .AddItem "Птичкин О.Т." .AddItem "Петренко В.В." .AddItem "Петрусев Ф.В." End With End Sub Private Sub TextBox1_Change() ' Переменная "MyText_Length" — длина введенного текста в TextBox1,"i" — номер строки в списке Dim MyText_Length As Integer, i As Integer ' Установка свойства ListBox1.MultiSelect в возможность выделения fmMultiSelectSingle в списке только одного элемента снимает все предыдущие выделения ListBox1.MultiSelect = fmMultiSelectSingle ' Установка свойства ListBox1.MultiSelect в возможность множественного выделения fmMultiSelectExtended ListBox1.MultiSelect = fmMultiSelectExtended ' Определяем длину введенного текста в поле ввода ЭУ TextBox1 MyText_Length = Len(Me.TextBox1.Text) ' Просмотр всего массива от "0" до верхней границы массива значений списка. Выражение "UBound(ListBox1.List( ))" можно заменить "ListBox1.ListCount -1". Отсчет строк и столбцов в ЭУ ListBox начинается с нуля, а не с единицы (особенность контрола) — так, например, первый элемент в списке, заполненном 10 строками, будет иметь индекс "0", десятый — "9" и т. п. For i = 0 To UBound(ListBox1.List( )) ' Если символы в поле ввода и левой части элемента массива совпали, тогда выделяется элемент в списке If Left(ListBox1.List(i, 0), MyText_Length) = TextBox1.Text Then ListBox1.Selected(i) = True End If Next End Sub
Систему поиска можно еще усовершенствовать (поиск будет осуществляться по совпадению в любой части элемента)
For i = 0 To UBound(ListBox1.List()) For n = 1 To Len(ListBox1.List(i, 0)) If Mid(ListBox1.List(i, 0), n, MyText_Length) = TextBox1.Text Then ListBox1.Selected(i) = True End If Next n Next i
Используя функцию UCase для преобразования в верхний регистр строки TextBox’а и заполняемых элементов ListBox’а, можно обеспечить поиск вхождений независимо от выбора раскладки клавиатуры.
Тем, кто захочет в своих приложениях использовать раскрывающиеся списки панелей инструментов, не обойтись без детального изучения объекта CommandBarComboBox. Он удобен в использовании и нагляден, но возможности программирования и заполнения его ограничены. Во-первых, количество элементов, которые можно «впихнуть» в список, ограничено числом 32767 — нюанс несущественный, вам вряд ли
понадобится такое количество элементов при работе с текстовой базой. Во-вторых, в объекте нельзя запрограммировать несколько колонок, придется обойтись одной. В-третьих, количество символов одного элемента (в т. ч. пробелов) не может превышать 255, а возможности управления объектом (что, кстати, аналогично и для всех объектов панелей инструментов) сводятся к реакции на клик мыши или ENTER. Как обойти первые два неудобства, будет показано далее.
К положительным моментам можно отнести время заполнения этого объекта по сравнению с ЭУ ListBox. А пока отмечу, что выбор объектов для заполнения и организация управления в программе — дело вкуса и умения разработчика.
Текстовый файл с последовательным доступом
Согласитесь, размещение данных для заполнения списков непосредственно в программе является не очень удачным решением. Чтобы отредактировать содержание списков, необходимо вносить изменения в проект и осуществлять перекомпиляцию.
Для начала определимся как будет организована текстовая база данных. Как было оговорено ранее, на предприятии ведется учет в таблице Excel (см. таблицу с условными данными), в которой информация из первых шести колонок должна быть отправлена в текстовый файл, а последующие столбцы являются конфиденциальными.
Так как имеет смысл дать возможность пользователю править файл в текстовом редакторе, то записи из ячеек предлагаю группировать следующим образом:
****************************************** Фирма А Код А Банк А МФО А Счет А Оплата А ****************************************** Фирма Б Код Б Банк Б МФО Б Счет Б Оплата Б ****************************************** Фирма В Код В Банк В МФО В Счет В Оплата В
(строчки из символов * являются разграничением между реквизитами разных контрагентов).
При такой записи данных мы имеем структурную единицу содержимого файла — строку. В этом случае чтение и запись в файле проще организовать строка за строкой, т. е. последовательно. Подобные файлы называются файлами последовательного доступа.
Excel’евский макрос для записи в файл может быть таким:
Sub RecordDAT() Dim nFileNo As Integer, x As Long, i As Long Range("A1").Select 'Использование предусмотренной в программе возможности перемещения в диапазоне данных. Если в первой ячейке таблицы имеются данные, осуществляется переход к концу таблицы (до первой пустой ячейки в столбце), в противном случае выходим из макроса If Range("A2").Value <> "" Then Selection.End(xlDown).Select Else: Range("A1").Select MsgBox "База пуста или ошибка в формировании базы...", vbExclamation, "" Exit Sub End If 'Определяем номер последней строки с данными в Excel’евской таблице. i = ActiveCell.Row 'Используется функция FreeFile, возвращающая следующий свободный номер файла в ОС. Под этим номером будет открыт файл текстовой базы. nFileNo = FreeFile 'Открываем файл в режиме Output. В этом режиме всегда создается новый файл, а данные старого файла затираются. Место создания файла определяем после слова Open. Open "C:\Мои документы\Const.txt" For Output As #nFileNo 'Записываем последовательно разделительные символы с временем создания файла и данные из каждой ячейки. For x = 2 To i Print #nFileNo, "*******************" & Now & "***********************" Print #nFileNo, Cells(x, 1).Value Print #nFileNo, Cells(x, 2).Value Print #nFileNo, Cells(x, 3).Value Print #nFileNo, Cells(x, 4).Value Print #nFileNo, Cells(x, 5).Value Print #nFileNo, Cells(x, 6).Value Next 'Закрываем файл Close #nFileNo 'Сообщение об окончании формирования файла MsgBox "Выполнено заполнение базы отредактированными данными.", vbInformation, "" End Sub
Итак? текстовый файл сформирован. Заполним ListBox-данными из него:
Private Sub UserForm_Initialize() Dim FileNo As Integer ' Определяем строковые переменные для считываемых порций данных Dim sBuf1 As String Dim sBuf2 As String Dim sBuf3 As String Dim sBuf4 As String Dim sBuf5 As String Dim sBuf6 As String Dim sBuf7 As String ' Переменная — указатель номера строки ЭУ ListBox Dim x As Long ' Определяем количество колонок в списке равным шести ListBox1.ColumnCount = 6 x = -1 FileNo = FreeFile ' Ключевое слово Input указывает что информация считывается последовательно Open "C:\Мои документы\Const.txt" For Input As #FileNo ' Считывание производится до тех пор, пока не будет достигнут конец файла While Not EOF(FileNo) ' Переменная "х", перед началом цикла установленная в "-1", получает с началом считывания значение, равное 0, увеличиваясь на единицу после очередного заполнения строки ЭУ ListBox. x = x + 1 Line Input #FileNo, sBuf1 Line Input #FileNo, sBuf2 Line Input #FileNo, sBuf3 Line Input #FileNo, sBuf4 Line Input #FileNo, sBuf5 Line Input #FileNo, sBuf6 Line Input #FileNo, sBuf7 ' Так как в sBuf1 считываются разделительные символы между сгруппированными данными, то его значение параметра при заполнении ЭУ ListBox остается невостребованным и в список не заносится. Me.ListBox1.AddItem sBuf2 ListBox1.List(x, 1) = sBuf3 ListBox1.List(x, 2) = sBuf4 ListBox1.List(x, 3) = sBuf5 ListBox1.List(x, 4) = sBuf6 ListBox1.List(x, 5) = sBuf7 Wend Close #FileNo End Sub
Добавив в форму TextBox’ы, можете сделать работу с ЭУ ListBox более комфортной.
Private Sub ListBox1_Click() TextBoxNameOrg = ListBox1.Column(0) TextBoxCodOrg = ListBox1.Column(1) TextBoxBancOrg = ListBox1.Column(2) TextBoxMfoOrg = ListBox1.Column(3) TextBoxSchetOrg = ListBox1.Column(4) TextBoxPlatOrg = ListBox1.Column(5) SpinButton1.Value = ListBox1.ListIndex + 1 End Sub
Имена TextBox’ам даны осмысленные — благодаря этому, поработав над полосой прокрутки SpinButton и ЭУ Label, можно получить ускоренные методы навигации по списку. Например, в конце процедуры
инициализации пользовательской формы (UserForm_Initialize), после закрытия файла (Close #FileNo), пропишите установки для SpinButton:
SpinButton1.Min = 1 SpinButton1.Max = ListBox1.ListCount SpinButton1.SmallChange = 1 SpinButton1.Value = 1 Label1.Caption = SpinButton1.Value и добавьте процедуру: Private Sub SpinButton1_Change() Label1.Caption = SpinButton1.Value ListBox1.ListIndex = SpinButton1.Value — 1 End Sub
Пример заполнения пользовательской формы реальными данными показан на рис 2.
(Продолжение следует)
