Nota del 19/Jul/2006: Si quieres ver cómo usar una clase parecida para Visual Basic 2005 y C# 2.0, sigue este link.
La utilidad de esta clase es para hacer cálculos del tiempo que tarda un proceso en realizarse, por ejemplo para calcular lo que tarda un bucle, etc.
Debido a que la precisión del temporizador de Visual Basic no es demasiado buena, se usan funciones del API para calcular esos tiempos.
Inicialmente la hice con GetTickCount, pero después "me enteré" (viendo la ayuda del API de Windows), que hay otra función con más precisión aún... es la función timeGetTime, que usa lo que llaman el temporizador multimedia.
La precisión de esta función llega a ser de UN milisegundo, frente a los 55 milisegundos de GetTickCount, al menos en Windows 95 (y parece ser que también en Windows 98)El concepto de la clase no es nuevo, de hecho lo he visto implementado de forma más o menos parecida en varios sitios y por diferentes autores, a los que agradezco que me resultara fácil crearla... lo que no pueda hacer un Copy & Paste y un par de modificaciones... je, je.
Tampoco es nada del otro mundo, lo que se necesita es un par de métodos:
Uno que Inicie el temporizador y otro que lo termine. Después alguna forma de saber cuánto ha sido ese tiempo y asunto arreglado.En la clase que te muestro, se puede obtener el tiempo transcurrido de dos formas, (en dos funciones expuestas por la clase), una de ellas devuelve una cadena formateada con el tiempo transcurrido que además se encarga de detener el temporizador y que permite indicarle, mediante un parámetro, si el resultado debe mostrarlo usando milisegundos, segundos, etc. Realmente lo que hace es dividir el tiempo total por el valor del intervalo que le indicamos; por defecto lo muestra en segundos.
La otra forma de saber el tiempo transcurrido es obteniendo los milisegundos transcurridos, en esta función no se detiene el temporizador ni se formatea el resultado, el valor se devuelve como un LONG.También se le puede indicar que función del API queremos usar para los cálculos, ésta se hace mediante la propiedad TimerType, que puede aceptar dos valores, según la función que queramos utilizar y que está enumerado para que sea fácil de indicar, ya que el nombre de los valores coinciden con los nombres de las funciones.
Pero veamos el código de la clase, que está más o menos comentado y que no te dará quebraderos de cabeza para entenderlo.
Nota del 09/Jul/2003:
Este es el código modificado con fecha 09/Jul/2003, prácticamente es el mismo que el usado en el año 98, pero con algunos cambios y añadidos para poder usar las clases mejoradas en Windows NT/2000/XP.
Pulsa en este link para bajarte el proyecto de prueba. (tGetTimer.zip 6.48 KB)
En este ejemplo también hay un control de usuario que sirve para mostrar líneas de separación con aspecto 3D.Nota:
En este fichero se incluye ahora la nueva clase modificada con fecha 09/Jul/2003.
Además he modificado el proyecto ya que referenciaba incorrectamente a la clase y el control.
'------------------------------------------------------------------------------ ' cGetTimer (16/Jun/98) ' Clase para calcular el tiempo entre eventos, etc. ' ' Ampliada para usar distintas funciones del API (29/Ago/98) ' Nuevos métodos/propiedades usando APIs especiales para NT/2000 (27/Oct/00) ' Comprobado en Windows XP Professional (09/Jul/03) ' ' Para usarla: ' StartTimer Iniciar el temporizador ' StopTimer Finalizar la cuenta ' ElapsedTimer Mostrar el tiempo transcurrido, formateado ' --- Nuevas propiedades --- ' TimerType El temporizador a usar ' TotalElapsedTime El número de milisegundos transcurridos ' ' TimerPerformanceFrecuency ' TimerPerformanceCounter ' ' ©Guillermo 'guille' Som, 1998-2003 ' ' En esta clase se usa el tiempo del sistema, es decir el número de ' milisegundos transcurridos desde que se inició Windows. ' Este temporizador vuelve a cero una vez transcurridos 49.7 días, ' (2^32 milisegundos), ' por tanto el cálculo del tiempo transcurrido puede no ser exacto, ' dependiendo de cuándo se inició y terminó la cuenta. '------------------------------------------------------------------------------ Option Explicit ' '------------------------------------------------------------------------------ ' Se puede usar timeGetTime si se quiere mayor precisión, ' ya que esta función tiene una precisión de: ' 1 milisegundo en Windows 95, y de ' 5 milisegundos o más, (es configurable), en Windows NT ' Private Declare Function timeGetTime Lib "winmm.dll" () As Long ' ' Sólo para Windows NT/2000/XP ' Para averiguar si se dispone de temporizador de alta precisión ' y configurar la precisión de timeGetTime() ' ' Nota: El valor asignado a los parámetros Currency hay que multiplicarlo por 10000 Private Declare Function QueryPerformanceCounter Lib "kernel32" _ (ByRef lpPerformanceCount As Currency) As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" _ (ByRef lpFrequency As Currency) As Long ' ' Texto basado en la descripción de: ' High-Resolution Timer (Platform SDK / Windows User Interface) ' La función QueryPerformanceCounter devuelve el valor actual del temporizador ' de alta precisión (si es que el sistema tiene uno). ' Se puede usar para calcular intervalos de tiempo usando la precisión de ' un temporizador de alta precisión (o resolución). ' Por ejemplo, suponiendo que QueryPerformanceFrequency indicara que la frecuencia ' del temporizador de alta precisión es de 50000 por segundo. Si la aplicación ' llamara a QueryPerformanceCounter inmediatamente antes y justo después de la ' sección de código a temporizar, y que estos valores fuesen 1500 y 3500, ' esto indicaría que el tiempo transcurrido es de .04 segundos (2000 ciclos) ' ' 'Private Declare Function timeBeginPeriod Lib "winmm.dll" _ ' (ByVal uPeriod As Long) As Long 'Private Declare Function timeEndPeriod Lib "winmm.dll" _ ' (ByVal uPeriod As Long) As Long ' '------------------------------------------------------------------------------ ' La precisión de GetTickCount es (aproximadamente) ' de 10 milisegundos en Windows NT 3.5 o superior ' de 16 ms. en Windows NT 3.1 ' de 55 ms. en Windows 95 o superior ' Private Declare Function GetTickCount Lib "kernel32.dll" () As Long '------------------------------------------------------------------------------ ' Valores del tipo de timer a usar Public Enum eTipoTimer eGetTickCount '= 0 eTimeGetTime '= 1 End Enum ' Variables locales para los cálculos ' Private mc_StartTimer As Currency Private mc_EndTimer As Currency Private mc_Frecuencia As Currency ' Private m_TimerType As eTipoTimer Private m_StartTimer As Long Private m_EndTimer As Long Private m_LastTime As Long ' Último tiempo calculado (11/Mar/99) Public Function ElapsedTime(Optional Intervalo As Long = 1000) As String ' Mostrar el tiempo transcurrido ' ' Intervalo se usará para la forma de mostrar el tiempo transcurrido ' ' Detener el timer If m_EndTimer = 0 Then StopTimer End If ' ' No admitir números negativos ni cero If Intervalo < 1 Then Intervalo = 1000 ' ' Devolver una cadena formateada con el tiempo ElapsedTime = Format$(CDbl(m_EndTimer) / Intervalo, "0.0####") ' si se quiere usar el TimerPerformanceCounter 'ElapsedTime = Format$((mc_EndTimer / mc_Frecuencia) * 1000 / Intervalo, "0.0####") End Function Public Sub StopTimer() ' Detener el timer ' ' El tiempo de diferencia puede no ser "exacto", ' ya que se reinicia cada 49.7 dias... (2^32 milisegundos) ' El timer se pone a cero cuando se inicia el sistema. If m_TimerType = eTimeGetTime Then 'mc_EndTimer = TimerPerformanceCounter - mc_StartTimer m_EndTimer = timeGetTime() - m_StartTimer Else m_EndTimer = GetTickCount() - m_StartTimer End If ' m_LastTime = m_EndTimer End Sub Public Sub StartTimer() ' Iniciar el timer m_EndTimer = 0 If m_TimerType = eTimeGetTime Then 'mc_Frecuencia = TimerPerformanceFrecuency 'mc_StartTimer = TimerPerformanceCounter m_StartTimer = timeGetTime() Else m_StartTimer = GetTickCount() End If End Sub Public Property Get TimerType() As eTipoTimer ' Devolver el tipo de timer que se usa TimerType = m_TimerType End Property Public Property Let TimerType(ByVal vNewValue As eTipoTimer) ' asignar el tipo de timer a usar m_TimerType = vNewValue End Property Private Sub Class_Initialize() ' Valor por defecto 'm_TimerType = eGetTickCount m_TimerType = eTimeGetTime ' Este es más preciso (11/Mar/99) End Sub Public Property Get TotalElapsedTime() As Long ' Mostrar el tiempo transcurrido en el último cálculo, ' incluso mientras se está calculando TotalElapsedTime = m_LastTime ' m_EndTimer End Property Public Property Get TimerPerformanceFrecuency() As Long ' Devuelve la frecuencia del temporizador de alta precisión (27/Oct/00) ' Dim curFrecuency As Currency Dim ret As Long ' ret = QueryPerformanceFrequency(curFrecuency) If ret = 0 Then ' No hay un temporizador de alta precisión TimerPerformanceFrecuency = 0 Else ' Devolver el valor de la frecuencia por cada segundo ' (multiplicar por 10000 ya que el valor devuelto viene con decimales) TimerPerformanceFrecuency = curFrecuency * 10000 End If End Property Public Property Get TimerPerformanceCounter() As Currency ' Contador del temporizador de alta precisión actual (27/Oct/00) ' Esta función se usará junto con TimerPerformanceFrecuency, ' para averiguar el lapso transcurrido entre dos periodos de tiempo ' ' Los milisegundos transcurridos será: ' la diferencia entre dos llamadas a esta propiedad ' dividido por el valor indicado por TimerPerformanceFrecuency ' ' Nota: Este resultado será casi igual que una llamada a timeGetTime, ' aunque algo más precisa. ' Dim curFrecuency As Currency Dim ret As Long ' ret = QueryPerformanceCounter(curFrecuency) If ret = 0 Then ' No hay un temporizador de alta precisión TimerPerformanceCounter = 0 Else ' Devolver el valor del contador ' (multiplicar por 10000 ya que el valor devuelto viene con decimales) TimerPerformanceCounter = curFrecuency * 10000 End If End Property
Para usarlo se haría algo como esto:
'Una referencia para poder usar la clase Dim tGetTimer As cGetTimer 'Creamos una nueva instancia de la clase Set tGetTimer = New cGetTimer 'Asignamos el tipo de temporizador a usar With tGetTimer 'Indicarle el tipo de función a usar .TimerType = eGetTickCount '---El bucle de Integer 'Iniciamos el temporizador .StartTimer For nRep = 1 To MaxRep For intCount = 1 To MaxBucle Next Next 'Detenemos el temporizador .StopTimer DoEvents 'Mostramos el tiempo en segundos -----v lblResultado(eInteger) = .ElapsedTime(0) ' Si se le indica un valor inferior a 1, ' se usa el valor por defecto: 1000 ' 'para mostrarlo en milisegundos: 'lblResultado(eInteger) = .ElapsedTime(1) End With 'Ya no necesitamos la clase Set tGetTimer = Nothing