1

I want to reference to this progress bar sample . http://spreadsheetpage.com/index.php/tip/displaying_a_progress_indicator/

About my vb working ,I m going to generate a report that using ADO in entire worksheet . As the report generation time is too long (1 min) , I want to implement a progress bar during the report generation .Btw , the report will be produced in a new excel file .

 Private Sub CommandButton3_Click()



    Dim sSQLQry As String
    Dim ReturnArray

    Dim Conn As New ADODB.Connection
    Dim mrs As New ADODB.Recordset

    Dim DBPath As String, sconnect As String



    DBPath = ThisWorkbook.FullName


    sconnect = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
    Conn.Open sconnect

   sSQLSting = "..."

   Set rs = Conn.Execute(sSQLSting)

   j = 6

    Do While Not rs.EOF
with thisworkbook.worksheets("report")
.Cells(j, 1) = rs.Fields(0).Value
.Cells(j, 3) = rs.Fields(2).Value
.Cells(j, 4) = rs.Fields(3).Value
.Cells(j, 7) = rs.Fields(6).Value
End with 


 j = j + 1

  rs.MoveNext

Loop


rs.Close

Dim wb As Workbook
    Set wb = Workbooks.Add

    ThisWorkbook.Sheets("report").Copy Before:=wb.Sheets(1)

...copy Sheets("report") to wb ...

strFileName = "c:\Users\" & Environ("Username") & "\Desktop\" & ThisWorkbook.Sheets("report").Cells(1, 1) & ".xlsx"
'End With
wb.SaveAs strFileName

I read the progress bar codes . It needs to use the loop variable PctDone = Counter / (RowMax * ColMax). For my codes , it includes different works- SQL calculation , pasting on worksheets("report") , coping worksheets("report") to new workbook .Hence , I don't know how to fit my code with this progress bar application .

Reference to Progress bar in VBA Excel


If it is impossible to implement progress bar in my case , what can i do tho let the user know "Be patient to wait about 1 min "?

Community
  • 1
  • 1
evabb
  • 405
  • 3
  • 21
  • 1
    You can't calculate percent done without knowing a) the total number of items you're going to process (row count in the database) and b) a counter of the number of rows you've finished processing. The second is easy - add a variable that you increment on each pass through the loop. The first is possible only if you can determine how many rows there are before you start the loop - can you do that? – Ken White Aug 17 '16 at 02:49
  • @Ken White I don't know the exact row for each report ,as i use `End(xlUp).row` to finish the final report in new workbook .Also , i don't know the row that SQL is going to generate , as well as the time spending on producing and writing a new work bar . – evabb Aug 17 '16 at 02:57
  • You do not need to use a progressbar per se as @KenWhite mentioned you can't calculate the percentage. Having said that. There is an alternative. Let me search my project database. I have a sample and If I find it, I will post it. It involves listbox and a userform – Siddharth Rout Aug 17 '16 at 02:59
  • @Siddharth Rout I tried to use a userform that showing "Please wait one minute` But i find that it need to spend some times on loading the new userform . That makes the whole application much loading time . – evabb Aug 17 '16 at 03:04
  • 1
    If you don't know those two things, you can't display a progress bar that shows percent complete. You could display a marquee style progress bar (the one that just goes back and forth with the little green section but doesn't show how far along you are); you can probably find an example of doing so in VBA via Google. – Ken White Aug 17 '16 at 03:04
  • I am almost done... – Siddharth Rout Aug 17 '16 at 03:07
  • Have you tried using CopyFromRecordset to get the data into Excel rather than looping through each record? (e.g. `thisworkbook.worksheets("report").Range("A6").CopyFromRecordset rs` (Or is it `mrs`? You seem to have a typo in your code.) Then it may only take a second or so, and then you won't need the progress bar. – YowE3K Aug 17 '16 at 03:08
  • @YowE3K i don't use `CopyFromRecords‌​et rs` because of some reason that i forgot .Then i choose to use `.Cells(j, 1) = rs.Fields(0).Value` – evabb Aug 17 '16 at 03:15
  • I even like the "marquee style progress bar" suggested by @KenWhite. I have edited my post in include a link to show animated images on the form. There are many possibliities if you want ;) – Siddharth Rout Aug 17 '16 at 03:26
  • If you are feeling adventurous then more samples of progress bar can be found at [Pop up the Excel Statusbar?](http://stackoverflow.com/questions/10782394/pop-up-the-excel-statusbar) – Siddharth Rout Aug 17 '16 at 03:30
  • `CopyFromRecords‌​et` does flake out sometimes. Have you tried using`GetRows`? –  Aug 17 '16 at 03:39
  • Can you share what is in `sSQLSting` ? You can probably aggregate the data with PivotTable or Excel formulas to make it much faster. – Slai Aug 17 '16 at 03:48
  • willing to put some effort? You can either display a gif during your operation or just change your mouse pointer (cursor) to a animated gif (ani) during the operation, Read this : http://ashuvba.blogspot.com/2014/10/ajax-style-progress-display-in-vba.html – cyboashu Aug 17 '16 at 04:57

1 Answers1

2

You do not need to use a progress bar per se as you can't calculate the percentage of work done. In such a case, it is better to let the user know of what you(or the code is doing). You could use Application.StatusBar to update but how many of us actually look down there? Also there's nothing more fancy than a form popping up and updating you about the status... You can also use Animated GIFS on the userform if you want.

I tried to use a userform that showing "Please wait one minute` But i find that it need to spend some times on loading the new userform . That makes the whole application much loading time

Ok You never show progress in the UserForm_Initialize() event of the userform. Show the progress when the process actually starts. If required, move everything to UserForm_Activate() or in a click of a Commandbutton. I am using UserForm_Click() for demonstration purpose.

Let's say we have a userform which looks like below with a Frame and Listbox` control.

Put this code in the userform

Private Sub UserForm_Click()
    ListBox1.AddItem "I am performing something in a loop..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True

    For i = 1 To 10
        Wait 3
    Next i

    ListBox1.AddItem "I am now writing something to the workbook..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True

    Range("A1").Value = "Sid"

    ListBox1.AddItem "I am performing something again in a loop..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True

    For i = 1 To 10
        Wait 3
    Next i

    '
    '~~> And So on
    '
End Sub

Private Sub Wait(ByVal nSec As Long)
    nSec = nSec + Timer
    While nSec > Timer
        DoEvents
    Wend
End Sub

Logic:

  1. Before starting any process, add the description to the listbox. I have added sample processes and descriptions in the above code. Please amend them to suit your needs.
  2. Notice the line ListBox1.Selected(ListBox1.ListCount - 1) = True? This will ensure that the recent most entry is always selected. This also ensure that the Listbox scrolls to the latest entry if many things are added to the listbox.

In Action

enter image description here

EDIT

You have misunderstood how it works :)

  1. Add a listbox on the form as shown in the image above.
  2. Delete all code from the userform and replace it with this code

Now run the code.

Private Sub UserForm_Activate()
    ListBox1.AddItem "Generating random numbers..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True
    DoEvents

    For i = 1 To 1000
        For j = 1 To 1000
            ThisWorkbook.Sheets("content").Cells(i, j) = Rnd
        Next
    Next

    ListBox1.AddItem "Copying and working with Content sheet..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True
    DoEvents

    Row = ThisWorkbook.Sheets("content").Range("A" & Rows.Count).End(xlUp).Row

    Set wb = Workbooks.Add

    ThisWorkbook.Sheets("content").Copy Before:=wb.Sheets(1)

    wb.Sheets(1).Cells(Row, 1) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("A:A"))
    wb.Sheets(1).Cells(Row, 2) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("B:B"))
    wb.Sheets(1).Cells(Row, 3) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("C:C"))
    wb.Sheets(1).Cells(Row, 4) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("D:D"))
    wb.Sheets(1).Cells(Row, 5) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("E:E"))
    wb.Sheets(1).Cells(Row, 6) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("F:F"))
    wb.Sheets(1).Cells(Row, 7) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("G:G"))
    wb.Sheets(1).Cells(Row, 8) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("H:H"))
    wb.Sheets(1).Cells(Row, 9) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("I:I"))
    wb.Sheets(1).Cells(Row, 10) = Application.WorksheetFunction.Sum(wb.Sheets(1).Range("K:K"))

    ListBox1.AddItem "Saving File..."
    ListBox1.Selected(ListBox1.ListCount - 1) = True
    DoEvents

    strFileName = "c:\Users\" & Environ("Username") & "\Desktop\" & ThisWorkbook.Sheets("content").Cells(1, 1) & ".xlsx"

    wb.SaveAs strFileName
    ThisWorkbook.Sheets("content").Cells.Clear

    ListBox1.AddItem "Done!"
    ListBox1.Selected(ListBox1.ListCount - 1) = True
    DoEvents
End Sub
Siddharth Rout
  • 147,039
  • 17
  • 206
  • 250
  • i have added this userform and code .Then ,how to combine with my button ? When button1 is clicked, this userform opens .What is the procedures to combine with my button(run those actions) ? – evabb Aug 17 '16 at 04:24
  • If `Private Sub CommandButton3_Click()` launches this userform then in the userform's activate event, put all the code. Also if required, add `DoEvents` after every `ListBox1.Selected(ListBox1.ListCount - 1) = True` – Siddharth Rout Aug 17 '16 at 04:31
  • `ListBox1.AddItem "I am performing something in a loop..." ListBox1.Selected(ListBox1.ListCount - 1) = True` Error 424 Need object – evabb Aug 17 '16 at 06:43
  • No. you are doing it incorrectly. Put `userform.show` in `CommandButton3_Clic‌​k‌​()` and the commandbutton's existing code, move it to the above userform's activate event – Siddharth Rout Aug 17 '16 at 06:49
  • Now ,i have done the following procedures:1 ) create userform 2) put your code on UserForm_Click 3) add only 1 sentence on my clickbutton : `userform.show` 4) move all my commandbutton's existing code to userform's activate event – evabb Aug 17 '16 at 07:46
  • Now , when i press the command button , the userform comes out first . However ,the userform has nothing shown inside .As it freezes ,hangs and shows `no responses `on the title . After a while , the userform closes automatically and the report comes out . I don't know it is hardware problem or what – evabb Aug 17 '16 at 07:49
  • Did you add `DoEvents` as I mentioned above? – Siddharth Rout Aug 17 '16 at 07:53
  • @ Siddharth Rout Now i add `DoEvents` after every `ListBox1.Selected(L‌​istBox1.ListCount - 1) = True` 3 in total – evabb Aug 17 '16 at 08:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121129/discussion-between-siddharth-rout-and-evabb). – Siddharth Rout Aug 17 '16 at 08:02
  • I knew you were doing something wrong :D. I have updated the above post. See the edit – Siddharth Rout Aug 17 '16 at 10:11
  • thanks bro , i will try the code tmr .One more question .As i have 5 buttons to generate different kind of reports , the codes inside buttons should be different .In this case , should i create 5 more userforms and put those different codes inside respectively ?Any convenient ways? – evabb Aug 17 '16 at 10:33