Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VBA multi thread Progress Bar

Status
Not open for further replies.

PetersBase

Programmer
Nov 11, 2008
3
GB
Hi Experts,
I've spent many days searching on the internet for an answer to the following problem:
Using VBA in Excel, start a time consuming task such as an SQL query. While this task is underway, start a Progress Bar that increments with a preset time interval. When this bar reaches the maximum value, it re-sets to zero and starts again in a repetative manner. This is just an indicator that the SQL query task is still being processed. When the task ends, the Progress Bar closes. If the task is part of a "loop", it is easy to make a Progress Bar work in the manner described, by making use of "DoEvents" to free-up some some CPU time to update the Progress Bar. But many tasks do not have a repetative "loop" structure where this command can be inserted. Also I think that VBA does not support multi-tasking? Each task must function sequentially, and can't be run independently in parallel via a different "thread".

Is it possible to create two independent threads using API calls, or some other technique to solve this problem? I have included an example of the code that I'm tying to get to work without DoEvents, because it can't be inserted in some tasks. I am very new to VBA programming for Excel, and a simple solution would be much appreciated. A multi threading technique would "open the door" to other programming challenges. Thank you very much for any advice or help.
Code:
'Code example
'==========================
Private Sub Workbook_Open()
   UserForm1.Show False
End Sub

'==========================
'Code in UserForm1
Private Sub CommandButton1_Click()
   NextTime = Now + TimeSerial(0, 0, 3) 'Time increment set to 3 secs
   Application.OnTime NextTime, "ModuleTick" 'Update Progress Bar in 3 secs
   UserForm2.Show False 'Display Form containing Progress Bar
End Sub

Public Sub FormTick() 'Must be called from a Module (ModuleTick)
   Call ProgressBar   'Increment the Progress Bar
   NextTime = Now + TimeSerial(0, 0, 3)
   Application.OnTime NextTime, "ModuleTick" 'Re-call Progress Bar every 3 secs
End Sub

Private Sub CommandButton2_Click() 'Stop Progress Bar via Command Button
   Application.OnTime NextTime, "ModuleKillTick"
End Sub

Public Sub FormKillTick() 'Must be called from a Module (ModuleKillTick)
   Application.OnTime NextTime, "ModuleTick", , False 'Stop Progress Bar
   UserForm2.Hide
   Unload UserForm2
End Sub

'=================
'Code in UserForm2 
'Dummy Task

Sub UserForm_Activate() 'Start Task
   Dim i As Long
   i = 1
   While i < 10000 And Not blnQuit 'Command Button can end this loop
      Worksheets("Sheet1").Cells(i, 1).Activate
      Worksheets("Sheet1").Cells(i, 1).Value = "Test Data"
      i = i + 1
      [COLOR=red]DoEvents[/color red] 'Essential to allow Progress Bar up-date
   Wend
   Unload UserForm2
End Sub

'==================
Code in Module

Public NextTime As Variant
Public blnQuit As Boolean

Public Sub ModuleTick()
   UserForm1.FormTick
End Sub

Public Sub ModuleKillTick()
   blnQuit = True 'Stop loop
   UserForm1.FormKillTick
End Sub

Public Sub ProgressBar()
   UserForm2.Label2.Width = UserForm2.Label2.Width + 10 'Increment Progress Bar
   If UserForm2.Label2.Width >= UserForm2.Label1.Width Then
      UserForm2.Label2.Width = 0 'Reset Bar
   End If
End Sub
 
There are, basically, three situations:

1. You have a long-running process in your code (with or without a loop) into which you can put progress updates at suitable points. No problem.

2. You fire off an external process that runs in parallel to your code, and has some kind of indicator that you can check to see if it completes. You can code a progress bar in a loop waiting for the flag to be set. Again, no problem.

3. You fire off a process for which VBA waits. There is no multi-threading and there is nothing you can do in this case because your VBA doesn't get control.

I'm unclear as to what you are doing that is long running and allows your code to continue but into which you can't code either a loop or an update at various points.

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Hi Tony,

Thanks for your reply.
I think I'm in situation number 3, "You fire off a process for which VBA waits. There is no multi-threading and there is nothing you can do in this case because your VBA doesn't get control".
The long running process I have is a SQL query on a Server I have limited access to. I can only send a Query, and can't add any "loop" or "updates".
I guess I'm left with option 2, where I fire off an external process. Would mean that I have to have an external file attached with the Excel file, when I deploy the application to any PC?
Regards, Pete.
 
When you send the query, how do you know when it's finished? Does the VBA code 'hang' until it's done? If so, there isn't much you can do.

If you were to fire an external process, again, how would you know when it was done? It would have to set some kind of flag that you could pick up in VBA. And if the query itself doesn't do that then you would have to code it all yourself - it is possible but I don't know how to do it.

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Hi Tony,
Yes my VBA process does "sit and wait" until the Query has finished, then my code drops the results into a spreadsheet. I guess I will have to use a large MessageBox saying "Please wait ... processing", then close it when the Query is done.
I believe it's fairly easy to "talk" between two Workbooks, and they would each have their own "thread". Therefore a Userform in one Workbook could have the Progress Bar "ticking over", and the other Workbook has the Query task running. I'm not sure if the Progress Bar Userform can be displayed on top of any windows on show. The down side would be that you would have two Workbooks for the application.
I think I may try a few more things before I move on from this challenge.

Thanks for your help,
Pete.
 
I'm not sure about Excel, but in Word, having two documents would make no difference - the whole Word application runs in a single thread (Word does run some background tasks itself, but still within the same thread I believe).

IMHO, a message box as you describe is as good as a progress bar which doesn't have an end point to measure against - one of my pet hates is progress bars that get to the end and then start at the beginning again, they lead you to believe something that is not true.

I don't use SQL these days, and one so quickly forgets, but could you get or give an estimate of the time the query may take so you can say "this might take several minutes" or whatever it may be?

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
What is your actual code ?

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top