Вернулся
 Аватар для HackerVlad
1753 / 649 / 45
Регистрация: 10.09.2021
Сообщений: 2,801

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

27.09.2023, 11:31. Показов 7229. Ответов 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
1407 / 866 / 93
Регистрация: 08.02.2017
Сообщений: 3,699
Записей в блоге: 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
1407 / 866 / 93
Регистрация: 08.02.2017
Сообщений: 3,699
Записей в блоге: 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
1407 / 866 / 93
Регистрация: 08.02.2017
Сообщений: 3,699
Записей в блоге: 2
11.05.2024, 09:20
Когда искал, пример использования HeapWalk, то нашел это у The trick-а, в его блоге, там запись, кстати была тоже про Листбокс https://www.cyberforum.ru/blog... g2329.html
1
Вернулся
 Аватар для HackerVlad
1753 / 649 / 45
Регистрация: 10.09.2021
Сообщений: 2,801
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
1753 / 649 / 45
Регистрация: 10.09.2021
Сообщений: 2,801
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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru