-
Nov 18th, 2021, 09:09 PM
#1
Thread Starter
Hyperactive Member
How do I add combobox items more quickly?
Hello!
I need to fill a combobox with 400 items.
I use
Me.cboTest.AddItem sSomeString
Adding a single item takes 1 ms.
So filling the combobox with 400 items takes 400 ms.
This is a drastic delay as the form that shows this combobox appears with a delay of 400 ms.
Is there perhaps an API call to populate a combobox more quickly?
Or can I prevent it from redrawing? I have tried .Enabled = false and .Locked = true, but that wouldn't change anything.
Thank you!
Last edited by tmighty2; Nov 18th, 2021 at 09:16 PM.
-
Nov 18th, 2021, 09:30 PM
#2
Re: How do I add combobox items more quickly?
Setting .Visible=False while loading items then back to true once all are loaded should help to some extent.
Edit: My mistake. No increase on the combo box speed using this trick, likely because the drop down part is not visible until you click on it anyway.
The 400ms for 400 items seems pretty slow. I wonder what kind of system it is running on and what else if anythign it is doing to get the string that is added that might make it slower. In a test I ran here it easily loads 1000 strings in ~250ms
Last edited by DataMiser; Nov 18th, 2021 at 09:41 PM.
-
Nov 18th, 2021, 09:33 PM
#3
Thread Starter
Hyperactive Member
Re: How do I add combobox items more quickly?
Thank you, but it doesn't have any effect for me.
I have found a replacement for the combobox, so if nothing helps, I can use this one. It's pretty fast.
-
Nov 18th, 2021, 09:37 PM
#4
Re: How do I add combobox items more quickly?
I've never had a problem with AddItem, but here's a way to do it with API calls. There's not going to be anything faster than that.
EDIT: I just tested that Nirsoft code, and I'm getting about .6 seconds with the VB6 AddItem method and about .4 seconds with the API method. It's a bit better but nothing huge. And again, it's not going to get any better because going to the API is as good as it gets.
Last edited by Elroy; Nov 18th, 2021 at 09:44 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Nov 18th, 2021, 09:42 PM
#5
Re: How do I add combobox items more quickly?
I edited my post above ^ after testing it here I saw that there was no increase in speed.
-
Nov 18th, 2021, 10:26 PM
#6
Re: How do I add combobox items more quickly?
Do you REALLY need to put 400 items into a combobox????? I'd hate to be the user who had to scroll to #399!!! There MUST BE some other method to display those items and be made available for selection. Maybe they are numerical, or alphabetical? Then you could simply 'replace' the items in a combobox or listbox or listview as one scrolls the control. Would be a lot faster, I do believe. But even then, 400??? Can you break it down into 'subsections', where maybe something like 10 or 20 items are scrollable in a text box based upon some 'identifier' that could be in a combobox or listbox?
I've been a software designer, coder AND tester (the latter many years more than the former). In my dealings with software developers, I always look at it from a user's point of view...what makes sense? Is it right? Does it LOOK good? Do I have to jump through hoops to get a simple task done. I definitely would not be pleased if someone gave ME a combobox with 400 items in it. Anyway....if you continue in this vein and can't speed up your process, present something else to the user while your combobox is loading...to the user, then, that loading process is never even noticed. Just a thought.
Sam I am (as well as Confused at times).
-
Nov 18th, 2021, 10:50 PM
#7
Re: How do I add combobox items more quickly?
So maybe something like:
Code:
Option Explicit
Private Const ITEM_COUNT As Long = 1000
Private Const CB_ADDSTRING As Long = &H143&
Private Const CB_INSERTSTRING As Long = &H14A&
Private Const CB_INITSTORAGE As Long = &H161&
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hWnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" ( _
ByRef Frequency As Currency) As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32" ( _
ByRef PerformanceCount As Currency) As Long
Private mFrequency As Currency
Private Function GetTicks() As Double
'Returns a time in seconds.
Dim PerformanceCount As Currency
If mFrequency < 0 Then
'Not supported, substitute:
GetTicks = CDbl(GetTickCount()) / 1000
Else
QueryPerformanceCounter PerformanceCount
GetTicks = CDbl(PerformanceCount) / mFrequency
End If
End Function
Private Sub TicksInit()
If mFrequency = 0 Then If QueryPerformanceFrequency(mFrequency) = 0 Then mFrequency = -1
End Sub
Private Sub Form_Load()
Dim Items() As String
Dim I As Long
Dim SpaceReqd As Long
Dim Secs As Double
'Make up some text to squirt into Combo1's item list.
'We store preconverted ANSI here to save time:
ReDim Items(ITEM_COUNT - 1)
For I = 0 To ITEM_COUNT - 1
Items(I) = StrConv(Format$(I, "0000 ") _
& MonthName(I Mod 12 + 1) & " " _
& CStr(Rnd() * 10000&), _
vbFromUnicode)
SpaceReqd = SpaceReqd + LenB(Items(I)) + 1
Next
TicksInit
Secs = GetTicks()
SendMessage Combo1.hWnd, CB_INITSTORAGE, ITEM_COUNT, SpaceReqd
For I = 0 To ITEM_COUNT - 1
SendMessage Combo1.hWnd, CB_INSERTSTRING, I, StrPtr(Items(I))
'Or if Combo1.Sorted = True then use:
'SendMessage Combo1.hWnd, CB_ADDSTRING, 0, StrPtr(Items(I))
Next
Secs = GetTicks() - Secs
MsgBox "Items: " & Format$(ITEM_COUNT, "#,##0") _
& vbNewLine & vbNewLine _
& "Total: " & Format$(Secs, "#,##0.000000") _
& vbNewLine & vbNewLine _
& "Per item: " & Format$(Secs / ITEM_COUNT, "#,##0.000000")
End Sub
My results, IDE run, fairly slow PC by current standards:
Code:
---------------------------
Project1
---------------------------
Items: 1,000
Total: 0.084233
Per item: 0.000084
---------------------------
OK
---------------------------
-
Nov 19th, 2021, 01:56 AM
#8
Re: How do I add combobox items more quickly?
I also went back and added CB_SETITEMDATA messages to populate ItemData. Hardly increased the time much at all.
-
Nov 19th, 2021, 09:35 AM
#9
Thread Starter
Hyperactive Member
Re: How do I add combobox items more quickly?
I have found the perfect solution:
http://www.vbaccelerator.com/home/VB...x/article.html
It is ultra fast (500 items took 9 ms), and its methods and properties are just like the standard VB6 combobox.
-
Nov 19th, 2021, 07:36 PM
#10
Re: How do I add combobox items more quickly?
I went back once more and replaced the SendMessageA() by SendMessageW() calls and passed in Unicode text.
Slightly slower letting the conversion happen in the control itself, but still not bad.
-
Nov 20th, 2021, 11:48 AM
#11
Re: How do I add combobox items more quickly?
I decided to dig into this a little. I started by adding 40000 items to a ComboBox in VB6. This takes almost 6 seconds. I then decided to do the same test in VB.Net which also took around 6 seconds. However, in .Net the ComboBox's Items property has an AddRange method which allows you to add multiple items at once using an array. Surprisingly when I used AddRange, it took around 1.5 seconds, that's around 4 times faster! I then decided to dig deeper by looking at the source code for the AddRange method in the .Net Framework. I noticed a call to BeginUpdate before the items were added and a call to EndUpdate after the items were added. When I dug deeper, I found calls to SendMessage that prevented redrawing of the ComboBox while items were being added. I decided to do the same thing in VB6 and it boosted the performance by a factor of 3!
Here is the full VB6 code:-
Code:
Const WM_SETREDRAW = &HB
Private Declare Function SendMessageW Lib "User32.dll" (ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private g_items() As String
Const ITEMCOUNT = 40000
Private Sub Form_Load()
g_items = CreateItems
TestNormal
TestRedrawOff
End Sub
Private Sub TestNormal()
Combo1.Clear
t = Timer
For i = LBound(g_items) To UBound(g_items)
Combo1.AddItem g_items(i)
Next
Debug.Print "With redraw on: " & CStr(Timer - t)
End Sub
Private Sub TestRedrawOff()
Combo1.Clear
t = Timer
BeginUpdate
For i = LBound(g_items) To UBound(g_items)
Combo1.AddItem g_items(i)
Next
EndUpdate
Debug.Print "With redraw off: " & CStr(Timer - t)
End Sub
Private Sub BeginUpdate()
SendMessageW Combo1.hWnd, WM_SETREDRAW, 0, 0
End Sub
Private Sub EndUpdate()
SendMessageW Combo1.hWnd, WM_SETREDRAW, -1, 0
End Sub
Private Function CreateItems() As String()
Dim items(1 To ITEMCOUNT) As String
For i = 1 To ITEMCOUNT
items(i) = "Item " & CStr(i)
Next
CreateItems = items
End Function
The above produces the following output for time measurements on my PC:-
Code:
With redraw on: 5.410156
With redraw off: 1.847656
-
Nov 22nd, 2021, 10:06 AM
#12
Thread Starter
Hyperactive Member
Re: How do I add combobox items more quickly?
-
Nov 26th, 2021, 02:31 AM
#13
Re: How do I add combobox items more quickly?
Originally Posted by tmighty2
Nice find, thank you!
Yep
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|