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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Timer isnt working

Status
Not open for further replies.

vba317

Programmer
Mar 5, 2009
708
US
I have a string of queries to run and track the time it takes to run them all. I have been working on this since last Thursday. I read about using API calls but I couldnt figure out how to apply them to my situation so I thought I would try a timer. My code counts up fine but I can't figure out how to have count down. I picked queries that would run about five minutes to keep testing time down. So I would like my timer to start at 5 minutes than count down as the queries are processed. Any help is greatly appreciated.

Tom

Code:
Public Sub cmdProcess_Click()
Dim strQryName As String
Dim iTime As Integer
Dim iIntValue As Integer
Dim qryCnt As Integer
Dim strtitle As String
Dim mtrStatus As String
Dim StartTime As Long
Dim ElapsedTime As Long
Dim fIncludeCancel As Boolean
Dim mfCancel As Boolean
Dim mySeconds As Integer
Dim myMinutes As Integer
Dim strConvertedTick As String
Dim strTime As String
Dim StartTime1 As Long
Dim iTotalTime As Long
Dim iTimeRef As Long

Const secondsPerDay As Long = 86400
Const secondsPerHour As Long = 3600
Const secondsPerMinute As Long = 60
Const minutesPerHour As Long = 60

strtitle = "FrmMain"
'Start Timer
StartTime = GetTickCount
'Init Meter Section
Me!lblStatus.Caption = "Time Started at 5:00 minutes"
Me!mtrStatus.Width = 0
Me.Caption = strtitle
Me!cmdCancel.Visible = fIncludeCancel
DoCmd.RepaintObject
mfCancel = False
With DoCmd
.SetWarnings False
For qryCnt = 1 To 8
    Select Case qryCnt
        Case 1
        strQryName = "000_ClearRVUTable"
        iIntValue = 500
                .
                .
                .
     End Select
        
        'Take reading before query is executed
        'Orig Formula
        ElapsedTime = GetTickCount - StartTime ' find how long it's been
        'Try and count down
        
        Debug.Print GetTickCount
        Debug.Print StartTime
        'Starting point of 5 minutes
        iTimeRef = 5 * 60
        iTotalTime = (iTimeRef + ElapsedTime) - ElapsedTime
        
        'Convert Time to minutes and seconds
        mySeconds = ElapsedTime * 0.001
        myMinutes = mySeconds Mod secondsPerHour
        mySeconds = myMinutes Mod secondsPerMinute
        myMinutes = myMinutes / secondsPerMinute
        strTime = Format$(myMinutes, "00") & ":" & Format$(mySeconds, "00")
        .RepaintObject
        Me!lblStatus.Caption = "Query " & strQryName & " running " & strTime
        Me!mtrStatus.Width = iIntValue
        .OpenQuery (strQryName)
        .RepaintObject
Next qryCnt
.SetWarnings True
End With
End Sub
 
What is GetTickCount ?

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
 
Are you doing this as an exercise to show that you actually can do it, or is it to use in a real world application?

I ask because it is very hard to know in advance how long queries will take.

What I do is:
If I know I have 15 steps (queries) to complete, I display to the user:[tt]
Step 1 of 15
Step 2 of 15
...
Step 15 of 15[/tt]
Just to let them know the application is doing something and is going somewhere.

Or, very often I would do:[pre]
For I = 1 to rst.RecordsCount
Label1.Caption = “Record “ & I & “ of “ & rst.RecordCount
....
Next i
Label1.Caption = “Done.”[/pre]


Have fun.

---- Andy
 
No, I need to know how long because I have thirty clients that I am creating custom reports for. Each client has it's own database. When I am running the queries it is to update the client's monthly and quarterly reports. Depending on the size of the client the queries can take ten minutes to run or up to two hours. I can only process the files when I get notified. The reason why I need to know how long the files will take is I don't want to run the two hour files a couple of minutes before its time to go home.
 
I need to know how long
How do you expect to know how long the files will take before running the queries ?
How is the code you've posted related to this issue ?

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
The code I posted is my attempt at developing a program that will count the system time in ticks. The code I posted does count the ticks the system takes to process the query. But after doing more research I discovered a timer method that I can use. To answer your question I don't know in advance how long queries will take so I am going to guess at a start number and run the queries till I get the last query execution to 0. I will post my code, I know it isnt pretty but it does work. What I was really hoping to achieve was to have the counter moving while the query was executing, This code does not do that. But I do get the bar to move forward after the query is finished.

Code:
Public Sub cmdProcess_Click()
Dim strtitle As String
Dim mfCancel As Boolean
Dim sCalcTime As Single
Dim sStartTime As Single
Dim qryCnt As Integer
Dim strQryName As String
Dim iIntValue As Integer
Dim sTime() As Single
Dim sTotalTime As Single
Dim fIncludeCancel As Boolean
Dim strTime As String

strtitle = "FrmMain"
'Init Meter Section
Me!lblStatus.Caption = "Time Started at 0:55 seconds"
Me!mtrStatus.Width = 0
Me.Caption = strtitle
Me!cmdCancel.Visible = fIncludeCancel
mfCancel = True
'Start Timer
sCalcTime = 55
sStartTime = sCalcTime + Timer
With DoCmd
.SetWarnings False
For qryCnt = 0 To 7
DoCmd.RepaintObject
    Select Case qryCnt
        Case 0
        strQryName = "000_ClearRVUTable"
        iIntValue = 500
        Case 1
        strQryName = "000_del_ClearRptData"
        iIntValue = 1000
        Case 2
        strQryName = "005_PostDrProcs"
        iIntValue = 1200
        Case 3
        strQryName = "010_PostRVUs"
        iIntValue = 1600
        Case 4
        strQryName = "015_updt_SetCPTDesc"
        iIntValue = 2200
        Case 5
        strQryName = "020_updt_SetWorkRVU"
        iIntValue = 3000
        Case 6
        strQryName = "025_updt_CalcTotRVU"
        iIntValue = 3500
        Case 7
        strQryName = "030_ClearZeroRVU"
        iIntValue = 4000
        End Select
        ReDim sTime(0 To 7) As Single
        sTime(qryCnt) = Timer
        sTotalTime = sStartTime - ((sTime(0) + sTime(1) + sTime(2) + sTime(3) + sTime(4) + sTime(5) + sTime(6) + sTime(7)))
        strTime = (sTotalTime \ 60) & " min, " & (sTotalTime Mod 60) & " sec"
        .RepaintObject
        .OpenQuery (strQryName)
        .RepaintObject
        Me!lblStatus.Caption = "Query " & strQryName & " running " & strTime
        Me!mtrStatus.Width = iIntValue
        .RepaintObject
Next qryCnt
.SetWarnings True
End With
End Sub
 
>have the counter moving while the query was executing, This code does not do that

Most odd. I posted earlier on today with a comment that your timer code would not update during query processing (because the query blocks whilst it is running). And with a simple fix for your countdown. But it has vanished ...

I'm afraid that this new code seems to be a backwards step, though. Still, if it works for you that's fine.
 
Strongm, I looked through all my posts and I could not find anything from you. I also looked through my other post thread702-1698464. If you have a solution that counts through the query I would really appreciate it.

Tom
 
>could not find anything from you

No, I don't think it posted properly, so you wouldn't have done.

>a solution that counts through the query

I wasn't suggesting that I did, just that I had a fairly simple change to have your timer count down properly.

Having said that, I do have a method for counting through the query. It uses some rather advanced ideas, spawning a seperate thread ... here's a rough working outline (WARNING: VBA is resolutely single-threaded and doesn't really like being conned into running in multiple threads; do the wrong thing in the spawned threads and your program WILL crash, almost certainly back to the desktop)

Code:
[blue]Option Compare Database
Option Explicit

Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long
Private Declare Function TerminateThread Lib "kernel32" (ByVal hThread As Long, ByVal dwExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private hThread As Long, hThreadID
Private lTimer
Private StartTime As Long
Private iTotalTime As Long

Public Sub AsyncThread()
    ' Let this thread sleep for 10 seconds
    ' This is where your processing would go
    ' This example just sleeps its thread to emulatea query running
    
    Sleep 5000 ' 5 second query
    Sleep 2000 ' 2 second theory
    Sleep 3000 ' 3 second theory
    ' 10 seconds in total
    
    TerminateThread hThread, 0
    hThread = 0
    
    'Debug.Print lTimer & " Done"
End Sub

Public Sub Example()
    StartTime = GetTickCount
    iTotalTime = 10
    lTimer = SetTimer(0&, 0&, 1000, AddressOf nTimerHandler) ' Note that timer events are not exact
    ' spawn asynch processing ...
    hThread = CreateThread(ByVal 0&, ByVal 0&, AddressOf AsyncThread, ByVal 0&, ByVal 0&, hThreadID)
    CloseHandle hThread
End Sub

Public Sub nTimerHandler(ByVal hwnd As Long, ByVal uMSG As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    Dim ElapsedTime As Double
    ElapsedTime = (GetTickCount - StartTime) / 1000
    Debug.Print iTotalTime - Int(ElapsedTime) & " seconds"
    If ElapsedTime > iTotalTime Then KillTimer 0&, lTimer
End Sub[/blue]
 
You are right. If you heard an explosion in the last couple of minutes it was my brain! I can honestly say that I can understand about 20% of this routine. I really want to stress that I can't thank you enough! I am assuming that my code to update the form will belong in the example sub is that correct?

Tom
 
No. Would go in the AsyncThread, as the comment there tries to suggest.
 
And note that there are other ways of doing asynchronous queries, but that would involve a reasonably big change in your code.
 
strongm,
I have finally got a chance to try your code. The time in strTime is not updating. My third query takes the most time say 1 min 30 sec, instead of counting down the time stays. Also the captionbar freezes as well. After calculating the time of the queries is about 3 min , I adjusted the times to reflect this by changing the sCalcTime value to 170. So The query counting in the strCaption works. Through the different values of iIntValue1-8 I have the width of the status bar changing, but it only changes after a query gets executed not while it is executing. Is there a way of updating time while the query is executing?

Tom

Code:
Public Sub AsyncThread()
' Let this thread sleep for 10 seconds
' This is where your processing would go
' This example just sleeps its thread to emulates query running
    Dim strTitle As String
    Dim mfCancel As Boolean
    Dim sCalcTime As Single
    Dim sStartTime As Single
    Dim qryCnt As Integer
    Dim strQryName As String
    'Dim iIntValue As Integer
    Dim sTime() As Single
    Dim sTotalTime As Single
    Dim fIncludeCancel As Boolean
    Dim strTime As String
    Dim iIntValue1 As Integer
    Dim iIntValue2 As Integer
    Dim iIntValue3 As Integer
    Dim iIntValue4 As Integer
    Dim iIntValue5 As Integer
    Dim iIntValue6 As Integer
    Dim iIntValue7 As Integer
    Dim iIntValue8 As Integer
    Dim ElapsedTimeTotal As Double
    Dim iIntValueTotal As Integer
    Dim strCaption As String
    'StartTime = GetTickCount
    'iTotalTime = 180
    lTimer = SetTimer(0&, 0&, 1000, AddressOf nTimerHandler)    ' Note that timer events are not exact
    'Added code
    strTitle = "FrmMain"
    sCalcTime = 170
    'Init Meter Section
    Forms!FrmMain!lblStatus.Caption = "Time Started"
    Forms!FrmMain!mtrStatus.Width = 0
    Forms!FrmMain.Caption = strTitle
    Forms!FrmMain!cmdCancel.Visible = fIncludeCancel
    mfCancel = True
    'Start Timer
    sStartTime = sCalcTime + Timer
    With DoCmd
        .SetWarnings False
        For qryCnt = 1 To 8
            DoCmd.RepaintObject
            Select Case qryCnt
            Case 1
                strQryName = "000_ClearRVUTable"
                'iIntValue= value of width of caption
                '1440 twips = 1"
                iIntValue1 = 120
            Case 2
                strQryName = "000_del_ClearRptData"
                iIntValue2 = 120
            Case 3
                strQryName = "005_PostDrProcs"
                iIntValue3 = 2500
            Case 4
                strQryName = "010_PostRVUs"
                iIntValue4 = 220
            Case 5
                strQryName = "015_updt_SetCPTDesc"
                iIntValue5 = 220
            Case 6
                strQryName = "020_updt_SetWorkRVU"
                iIntValue6 = 140
            Case 7
                strQryName = "025_updt_CalcTotRVU"
                iIntValue7 = 140
            Case 8
                strQryName = "030_ClearZeroRVU"
                iIntValue8 = 150
            End Select
            ReDim sTime(1 To 8) As Single
            Debug.Print "qryCnt ", qryCnt
            iIntValueTotal = iIntValue1 + iIntValue2 + iIntValue3 + iIntValue4 + iIntValue5 + iIntValue6 + iIntValue7 + iIntValue8
            Debug.Print "iIntValueTotal ", iIntValueTotal
            sTime(qryCnt) = Timer
            Debug.Print "strTime " & sTime(qryCnt)
            sTotalTime = sStartTime - ((sTime(1) + sTime(2) + sTime(3) + sTime(4) + sTime(5) + sTime(6) + sTime(7) + sTime(8)))
            Debug.Print "sStartTime " & sStartTime
            Debug.Print "sTotalTime " & sTotalTime
            'Original code
            strTime = (sTotalTime \ 60) & " min, " & (sTotalTime Mod 60) & " sec"
            'Added code
            'strTime = strTime - ElapsedTimeTotal
            .RepaintObject
            Debug.Print "sTotalTime " & sTotalTime
            strCaption = "Query " & qryCnt & " of 8" & " running " & strTime & " remaining"
            Forms!FrmMain!lblStatus.Caption = strCaption
            Forms!FrmMain!mtrStatus.Width = iIntValueTotal
            Debug.Print "iIntValueTotal " & iIntValueTotal
            .RepaintObject
            .OpenQuery (strQryName)
            Forms!FrmMain!mtrStatus.Width = iIntValueTotal
            Debug.Print "iIntValueTotal " & iIntValueTotal
            .RepaintObject
        Next qryCnt
        Forms!FrmMain!lblStatus.Caption = "All Queries have completed !!"
        .SetWarnings True
    End With


    '    Sleep 5000    ' 5 second query
    '    Sleep 2000    ' 2 second query
    '    Sleep 3000    ' 3 second query
    ' 10 seconds in total

    TerminateThread hThread, 0
    hThread = 0

    'Debug.Print lTimer & " Done"
End Sub
 
I have noticed that when I stop the process of AsyncThread()
the elapsedtime counter starts to count. So how do I access this variable from the nTimerHandler sub?

Tom
 
Right - not quite sure where to start. If I get a chance to look at at this in more detail I will, but I'm a bit busy at the moment. One quick note - it is not a good idea to Debug.Print in the spawned thread (AsynchThread). Secondly ... well, unfortunatley (and I know it introduced some slightly advanced ideas) you seem not to have understood the example at all. For example why have you put "lTimer = SetTimer(0&, 0&, 1000, AddressOf nTimerHandler)" into AsynchThread? And why have you reatined your timer, which we know does not work. You don't need to do any timimg in AsynchThread, it would be handled (and was so handled in the example) by nTimerHandler
 
Sorry about that. I originally had all this code in the example sub. When I reread the other posts and realized that I put it in the wrong sub I cut and pasted too much. I will move it back. I appreciate any help you can give me whenever that is.

Tom
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top