Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.60/25: Рейтинг темы: голосов - 25, средняя оценка - 4.60
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786

Как добавить в список ListBox большое количество строк, чтобы это было быстро по времени?

27.09.2023, 11:31. Показов 7037. Ответов 125

Студворк — интернет-сервис помощи студентам
Всем привет! У меня есть листбокс List1 в VB6 и я пытаюсь добавить в этот список много строк, скажем 10 тысяч строк, но я хочу добавить их таким образом, чтобы они добавились быстро по времени, а не ждать целую секунду... Я этого делать не умею, поэтому помогите пожалуйста! Единственный лайфхак который я нашёл это сначала скрывать список а потом показывать так можно добавить в список много строк в 3 раза быстрее, но для 10 тысяч строк это всё равно занимает целых пол секунды времени...

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const LB_INITSTORAGE = &H1A8
Private Const LB_ADDSTRING = &H180
 
Private Sub Command1_Click()
    Dim i As Integer
    Dim tick As Long
    
    List1.Clear
    tick = GetTickCount
    
    For i = 0 To 10000
        List1.AddItem i
    Next
    Me.Caption = GetTickCount - tick ' 1311 ml
End Sub
 
Private Sub Command2_Click()
    Dim i As Integer
    Dim tick As Long
    
    List1.Clear
    tick = GetTickCount
    
    List1.Visible = False
    
    For i = 0 To 10000
        List1.AddItem i
    Next
    
    List1.Visible = True
    
    Me.Caption = GetTickCount - tick ' 468 ml
End Sub
 
 
Private Sub Command3_Click()
    Dim i As Integer
    Dim tick As Long
    Dim str As String
    Dim hwndList As Long
    
    str = "123"
    hwndList = List1.hwnd
    
    List1.Clear
    tick = GetTickCount
    
    'List1.Visible = False
    
    Debug.Print SendMessage(hwndList, LB_INITSTORAGE, 10001, CLng(LenB(str) * 10001))
    
    For i = 0 To 10000
        SendMessage hwndList, LB_ADDSTRING, 0, StrPtr(str)
    Next
    'List1.Visible = True
    
    Me.Caption = GetTickCount - tick ' 1310 ml
End Sub
Я начал читать в MSDN про сообщение LB_INITSTORAGE но у меня ничего не получилось почему-то всё равно строки в список добавляются очень медленно! Помогите плиз!

Добавлено через 24 минуты
Вопрос: почему не работает сообщение LB_INITSTORAGE?

Добавлено через 24 секунды
Скорость добавления в листбокс никак не изменилась!
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
27.09.2023, 11:31
Ответы с готовыми решениями:

Как быстро создать список на большое количество элементов?
День добрый! Ищу информацию по такому вопросу. Например, в С++ объявить массив с сотней элементов можно простой строкой. string...

Максимально быстро записать большое количество строк SQLite
Приветствую всех. Думаю из заголовка понятно в чём вопрос как максимально эффективно и быстро записать в таблицу базы данных SQLite большое...

Как сделать так чтобы из продуктов можно было добавить в блюда и это списывалось все на кухне
Как сделать так чтобы из продуктов можно было добавить в блюда и это списывалось все на со склада

125
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,673
Записей в блоге: 2
11.05.2024, 06:54
Студворк — интернет-сервис помощи студентам
HackerVlad, спасибо за подробную инструкцию, вижу с кириллицей там не работает, но это не суть важно, еще не очень понятно как получить адрес найденной строки, наверное как-то вычислять.
Цитата Сообщение от HackerVlad Посмотреть сообщение
мне интересен изначальный алгоритм поиска. Что ты ищешь в самом начале? Как ты определил заголовочную структуру листбокса? Как понял куда нужно записывать количество строк?
Если изначальн все правильно делать, процесс исследования листбокса можно описать так.. Нет ну конечн более правильно включить какой-нибудь дизассемблер и там все чик-пик, тык-мык, и бемс, но я описываю как я делаю. Во-первых нужен модуль, который я уже выкладывал, я его специально сделал, для таких вещей, по ходу дела туда что-то еще добавляется.
Сначала пишем такую процедуру
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Sub Example()
    Dim oList As ListBox, i&
    Dim pBuf&, pHdr&, he As PROCESS_HEAP_ENTRY
    Dim iArr%(), lArr&(), SA As SAFEARRAY1D
    
    Form1.Show 0 'запускаем форму немодально
    Set oList = Form1.List1
    oList.AddItem RandomString(8) 'Добавляем итемы в листбокс
    oList.AddItem RandomString(10)
    oList.AddItem RandomString(6)
    Stop
    
    For i = 0 To 2
        pBuf = 0: pHdr = 0
        oList.ListIndex = i 'устанавливаем "курсор" на следующую строку
'        Ищем в памяти свего процесса строку (pBuf), возвращаемоую методом "Text" объекта "oList" и заголовочный указатель(pHdr), в котором прописан адрес (pBuf) этой строки
        FindObjectDataPtr oList, "Text", pBuf, pHdr, , BSTR
        Debug.Print pBuf, pHdr
    Next
'    Stop
End Sub
По итогу работы видим такой вывод
Code
1
2
3
4
Example
 8552768       8268632 
 8552786       0 
 8552808       0
Видим, что "заголовок" (pHdr) нашелся только для первой строки. Это наводит на мысль (не сразу, но простепенно), что программе нужен только первый заголовок, адреса других строк она берет/вычисляет каким-то другим способом. Еще наводит на мысль, что все строки в одном буфере, поэтому у них один заголовок.
Проверяем смещения между буферами строк
?8552786-8552768
18
?8552808-8552786
22
Видим, что буферы фактически находятся рядом
Первая строка у нас 8*2 = 16 байт, если добавить нуль - еще +2 поолучится 18, вторая строка 10*2+2 = 22. Все сходится строки лежат в одном буфере, разделенные 2байтным нулем.
Теперь цикл можно убрать и оставить вычисление указателей только для первой строки. Далее нас интересуют параметры локаций (выделенной памяти), в которых расположен буфер и заголовок.
Visual Basic
1
2
3
4
5
6
7
8
9
    oList.ListIndex = 0 'устанавливаем "курсор" на первую строку
'    Ищем в памяти свего процесса строку (pBuf), возвращаемоую методом "Text" объекта "oList" и заголовочный указатель(pHdr), в котором прописан адрес (pBuf) этой строки
    VBMemHelper.FindObjectDataPtr oList, "Text", pBuf, pHdr, , BSTR
    he = GetAllocInfo(pBuf)
    Debug.Print "Buf: "; pBuf; he.lpData; he.cbData
    Stop
    he = GetAllocInfo(pHdr)
    Debug.Print "Hdr: "; pHdr; he.lpData; he.cbData
    Stop
Вывод:
Code
1
2
Buf:  92345280  92345280  256 
Hdr:  92348384  92348336  216
Как видим, начало локации буфера совпадает с адресом самого буфера. При этом размер локации выделен с запасом - 256 байт. Это наводит на мысль, что при необходимости увеличения буфера, память также будет довыделятся на величину, кратную 256.
Адрес заголовка строки pHdr, не совпадает с началом своей локации, а смещен от начала на 48 байт
Code
1
2
?92348384-92348336
 48
Далее рассуждаем, учитывая, что все строки лежат в одном буфере, и то что не найдены заголовки других строк, кроме первой, программа, как-то должна вычислять адрес любой строки, т.е. где-то должна быть информаия о смещениях каждой строки и скорее всего это должен быть массив, поскольку наиболее удобно это хранить в массиве. Также программа куда-то должна записывать общее колличество строк и возможно еще какие-то параметры.
Все выше-описаное вероятно хранится в локации/структуре заголовка, чтобы это выяснить мапим массивы типа long и integer на локацию заголовка. Сразу скажу, что все обнаружилось в лонг-массиве, там все параметры оказались четко по 4байтовой "сетке".
Visual Basic
1
2
3
4
5
6
7
8
9
    he = GetAllocInfo(pHdr) 'получаем информацию о локации заголовка
    'Мапим на заголовочную структуру массив типа Long
    SA.cDims = 1: SA.cbElements = 4
    SA.pvData = he.lpData: SA.Bounds.cCount = he.cbData \ 4
    CopyMemory ByVal ArrPtr(lArr), VarPtr(SA), 4
    
    Stop
    
    CopyMemory ByVal ArrPtr(lArr), 0&, 4
Продолжение следует..
Миниатюры
Как добавить в список ListBox большое количество строк, чтобы это было быстро по времени?  
1
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,673
Записей в блоге: 2
11.05.2024, 09:11
Как видим на скрине, в 12 элементе массива значение равное pBuf указатель на буфер строк по смещению 48 байт. В 8 элементе цифра 3, которая равна числу добавленных элементов. В 14 элементе число 256, равное ранее выясненому размеру локации буфера. В 15 - число равное общей длине всех строк с нулями: (8+10+16)*2+2*3 = 54.
Все очень легко проверить, когда код стоит на стопе, в Immediate вводим ?oList.AddItem "gfgfg" и видим как меняются значения в 8 и 15 элементах.
Где-то должна быть информация об смещениях строк, подозрение сразу падает на указатель в lArr(10) и число 32 рядом с ним. Получаем информацию об этом указателе и мапим на него массив.
Visual Basic
1
2
    he = GetAllocInfo(lArr(10))
    SA.pvData = he.lpData: SA.Bounds.cCount = he.cbData \ 4
Из полученной инормации, видим, что по этому указателю область размеров 256 байт,также как и буфер строк и в ней содержится массив тех самых смещений, как и ожидалось. Как видно, элементы там идут по сетке 8 байт. Число 32 - это максимально доступное колличество при размере 256 байт: 256/8 = 32. При достижении максимума, надо полагать алгортим будет расширять локацию(реаллочить) на 256 байт, также как со строковым буфером.
Дальше оставалось только продумать алгоритм добавления строк и прописывания всех параметров в заголовочную структуру. Потом еще идея пришла использовать HeapWalk для поиска указателей, более компактно и быстро.. Однако HeapWalk это конечно вещь специфическая, она требует блокировки кучи, на время ее работы, однако работает очень быстро (пример использования, кстати, брал у Трика), но есть некоторые сомнения в абсолютной надежности ее работы.
Миниатюры
Как добавить в список ListBox большое количество строк, чтобы это было быстро по времени?  
1
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,673
Записей в блоге: 2
11.05.2024, 09:20
Когда искал, пример использования HeapWalk, то нашел это у The trick-а, в его блоге, там запись, кстати была тоже про Листбокс https://www.cyberforum.ru/blog... g2329.html
1
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786
11.05.2024, 13:32  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
там запись, кстати была тоже про Листбокс https://www.cyberforum.ru/blog... g2329.html
Я этот пример нашёл ещё несколько лет назад и был очень вдохновлён этим, я даже и не знал тогда на то время, что простой листбокс в VB можно превратить в такую красоту. Очень долгое время я восхищался и использовал его этот класс пользовательской отрисовки листбокса. Однако, настало время когда мне пришлось отказаться от его этого супер-кода и перестать использовать его класс, потому что его класс нацелен на стандартный листбокс, а сейчас я использую API листбокс, так как только API листбокс позволяет через API отключать перерисовку для быстрого добавления огромного количества строк в листбокс. Сейчас я использую юникодный контрол от Krool под названием ListBoxW который уже имеет событие пользовательской отрисовки листбокса. То есть там прям такое событие есть в дизайнере IDE оно легко открывается и при этом класс от The Trick уже становится не нужен. Но пользовательскую отрисовку листбокса и эту идею я использую до сих пор, чтобы в листбоксе показывать иконки файлов, имена файлов, и свойства файлов, чтобы листбокс был красивым.
1
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
13.05.2024, 09:48
HackerVlad, привет
В VBA я просто присваиваю листбоксу массив (лучше - стринговый)
0
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786
13.05.2024, 15:55  [ТС]
Jack Famous, да я знаю в VB.Net тоже самое так можно, но эта тема для VB6.

Добавлено через 7 минут
testuser2 дал очень хороший ответ, как напрямую в память перезаписать список строк листбокса. Но его код не на всех системах, к сожалению, будет работать. Заголовочная структура листбокса, в разных системах почему-то всегда разная. Хотя если использовать именно листбокс без красивостей, то для всех систем одинаково. И значит, что если использовать технологию testuser2 то можно уверенно сказать, что без красивостей будет работать во всех системах Windows. Но вот с красивостями уже сложнее - уже память становится совсем другая.

Другими словами, если кому-то красивости не нужны, и если без манифеста, то можно спокойно быть уверенным, что во всех системах будет работать прямая перезапись памяти листбокса. Зато скорость добавления будет 32 млск даже для 100 тысяч строк добавления.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
13.05.2024, 15:55

Вывести файл на экран, чтобы в каждой строке было не больше 40 символов, и количество строк было минимальным
Дано файл f. Вывести этот файл на экран так что бы в каждой строчке было не больше, чем 40 символов и количество строк было минимальным.

Как исправить, чтобы количество столбцов и строк StringGrid было таким, как ввел пользователь
Подскажите, в чем дело, программа создает двумерный массив элементы которого вводят с клавиатуры, ввод осуществляется в stringGrid. При...

Как добавить значения с Листа в Listbox, если количество строк может меняться
Есть Лист с уже заданными значениями, но они могут изменяться (добавляться, удаляться). Нужно добавить этот столбец в Listbox. Помогите...

Как сделать так,чтобы количество строк и столбцов массива можно было менять через меню?
как сделать так,чтобы количество строк (n) и столбцов(m) массива можно было менять через меню? весь код #include...

Поиск минимального времени выполнения теста, чтобы количество набранных баллов было максимальным
Здравствуйте! Подскажите пожалуйста, в чем ошиблась у меня массив Examen структур с данными о номере Nomer. Для каждого номера дано время...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
126
Ответ Создать тему
Новые блоги и статьи
Море в объективе
kumehtar 06.07.2026
Хотел написать много проникновенных слов, но передумал. Оно само - говорит. Кто слышит тот слышит.
Оказывается, Unreal Engine позволяет качество на порядки выше, чем было в Lineedge
Etyuhibosecyu 05.07.2026
Жаль, конечно, что я не узнал об этом, пока Lineedge существовала, а то бы Noname2331 написал, что волки превращаются в пиксельную кашу, а я бы его попросил скачать какую-нибудь бриллиантовую или Pro. . .
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru