PDA

Click to See Complete Forum and Search --> : Way around DoEvents taking forever


BrendanDavis
Oct 30th, 2006, 05:40 PM
Everyone knows DoEvents takes forever if you're doing anything lengthly with it(adding a large amount of items to a listbox, for example). But it lets you do other tasks, so it's great in that respect.

But let's say you want a label to be a real-time display of items being added to the listbox(like a counter), but you're adding a large number of items to the listbox and you don't want it to take FOREVER. There's a way around it, and it's very simple. I'm sure a lot of people already know about this, but for the folks who don't(possibly new to VB), this will let you have the best of both worlds with DoEvents:

Public Function sysDoEventsIf(doIf As Integer, isDivisibleBy As Integer) As Boolean

On Error GoTo endWithoutEvents

If doIf = 0 Then GoTo endWithoutEvents
If doIf < isDivisibleBy Then GoTo endWithoutEvents

Dim divisResult As Integer
divisResult = (doIf / isDivisibleBy)

If divisResult < 1 Then GoTo endWithoutEvents
If InStrB((doIf / isDivisibleBy), ".") > 0 Then GoTo endWithoutEvents

sysDoEventsIf = True
DoEvents

endWithoutEvents:

End Function



What does that do? It checks if the variable you specify is equally divisible by anothe specified number, and then ONLY does "DoEvents" if it is. How is that useful? Here's an example:

Private Sub Command1_Click()

Dim d As Boolean
Dim i As Integer

For i = 0 To 24999
d = sysDoEventsIf(i, 100)
List1.AddItem "Item " & i, i
If d = True Then Label1.Caption = "Items: " & List1.ListCount
Next i

Label1.Caption = "Items: " & List1.ListCount

End Sub



This button(Command1) adds 25,000 items to a listbox. The kicker is it will only call DoEvents to free up the process if the current step(defined as "i") is divisible by 100. So rather than calling DoEvents on EVERY step(making the process take a lot longer), it will only call it every 10 steps!

You can make it call DoEvents as often as you want. Change the function call to "d = sysDoEventsIf(i, 1000)" and it will only call DoEvents if the current step integer is divisible by 1000 evenly.



NOTE: The larger the number you're trying to divide it by, the quicker it goes. The smaller the number you're trying to divide it by, the slower it will go.



Hope this helps some folks with... whatever.



-Brendan

bushmobile
Oct 30th, 2006, 06:26 PM
this is typically done with Mod:Private Sub Command1_Click()
Dim I As Integer

For I = 0 To 24999
List1.AddItem "Item " & I
If I Mod 1000 = 0 Then DoEvents
Next I
End Sub

BrendanDavis
Oct 31st, 2006, 08:24 AM
this is typically done with Mod:Private Sub Command1_Click()
Dim I As Integer

For I = 0 To 24999
List1.AddItem "Item " & I
If I Mod 1000 = 0 Then DoEvents
Next I
End Sub

Hmm, I'm not familiar with Mod. See, learn something new every day. Does it check if it's equally divisible each time or does it just check if it is equal to 1000(or whatever integer you specify)?

bushmobile
Oct 31st, 2006, 08:27 AM
it returns the remainder: Mod (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbenlr98/html/vaoprmod.asp)

CVMichael
Oct 31st, 2006, 08:32 AM
First of all, you posted in the wrong forum, this is the CodeBank, where you post working code pro programs that you think other people might need (and is not already in the CodeBank).

This thread should be moved.

About your question:
Mod means Modulus, and it calculates the reminder from a division.
For example:
you divide 9 by 5, you get the result 1 (5 does not go into 9 two times), and the reminder is 4.

So, as I was saing Mod returns the reminder of a division: 9 Mod 5 = 4

So this line:
If I Mod 1000 = 0 Then DoEvents
Executes DoEvents every 1000'th time, because only then the reminder is equal to 0...

BrendanDavis
Oct 31st, 2006, 01:17 PM
CVM, my codes DOES work. Just because it's a longer way around, doesn't mean it doesn't work.

...and my apologies, I was just trying to help. I could have benefit from examples like this, however unprofessional they may be, when I was just starting out.

CVMichael
Oct 31st, 2006, 01:50 PM
Sorry, when I first read you post, it looked more like a question to me rather than a CodeBank entry.

bushmobile
Oct 31st, 2006, 02:25 PM
whilst your code does work and does reduce the speed of the loop in comparison to calling DoEvents everytime, it still causes the loop to suffer a significant drop in performance. Consider this:Private Sub Command1_Click()
Dim N As Long, lTimer As Long, lRet As Long
lTimer = GetTickCount
For N = 0 To 20000000
lRet = N
Next N
Print GetTickCount - lTimer
End Subthat takes 16~31 milliseconds on my comp to execute.

With If N Mod 1000 = 0 Then DoEvents in the loop it takes ~500 milliseconds

and with bln = sysDoEventsIf(N, 1000) in the loop it takes ~13750 milliseconds.

DigiRev
Nov 11th, 2006, 01:56 AM
Or use the GetInputState API function.

If GetInputState Then DoEvents

There's an even better API function to use, but I forget what it is.

Comintern
Nov 15th, 2006, 04:12 PM
There's an even better API function to use, but I forget what it is.This (http://www.vbforums.com/showthread.php?t=315416) should jog your memory.