De múltiples subprocesos temporizadores

De múltiples subprocesos temporizadores


Nunca añadido un TTimer para su aplicación sólo para encontrar que su caso no se ejecuta porque el principal VCL hilo está ocupado?

Desarrolladores de Delphi septiembre de 2000
Copyright de Pinnacle Publishing, Inc. Todos los derechos reservados.el Real Temporizador por Favor, Ejecute?

Steve Zimmelman



la Necesidad es a menudo la madre de la invención, y esta vez no fue la excepción. Mientras yo estaba trabajando en algunas de Microsoft Word/Excel integración, surge un problema cuando yo era procesamiento de documentos con la propiedad Visible en False. Word mostrará un cuadro de diálogo (que el usuario no pueda ver) y esperar una respuesta. Bueno, no hace falta decir que esto hizo que la aplicación aparezca como si se colgaba. Necesitaba una forma de tiempo en el proceso y manejar las cosas, en caso de tomar demasiado tiempo. Así que me golpeó un TTimer componente en el formulario, establezca el intervalo de 1.000 (un segundo), y se contó el número de veces que el evento de temporizador se ejecuta. Suena bien, ¿verdad? Mal! Cuando el cuadro de diálogo de Word se mostró a sí misma, fue el uso de los principales VCL hilo, que a su vez no estaba dando paso a otros procesos, incluyendo TTimer. Así, una vez más, la aplicación apareció como si se colgó.



La solución fue crear un hilo que podría controlar el tiempo, no importa lo ocupado que el principal VCL hilo. Pero la creación de un hilo cada vez que he necesitado esta funcionalidad no parece la mejor solución a partir de un objeto-orientado punto de vista. Así que he creado un nuevo componente Timer que crear y utilizar su propio hilo de rosca interno y ejecutar un método de evento en un intervalo de tiempo específico.



La TThreadTimer componente es el resultado. Se trata de una simple subclase de TComponent que gestiona una rosca interna. El hilo es creado y destruido por el componente. Cuando la propiedad Enabled es Cierto, el hilo es creado, y cuando es Falsa, es destruido. Yo también quería asegurarse de que el hilo no se crean en el modo de diseño. Así que he comprobado la ComponentState antes de ejecutar cualquiera de los métodos:



Procedimiento TThreadTimer.SetEnabled(Valor:Boolean)

Begin

& nbsp & nbsp & nbsp If (Valor <> FEnabled), a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FEnabled := Valor

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // no Crear o Matar el hilo a menos que

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // se ejecuta la aplicación.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si No (csDesigning En ComponentState)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp, a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FEnabled, a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FTimerEventCount := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread := TTheThread.Create(Self)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp End Else Begin

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp KillThread

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Final

Fin




he utilizado un método llamado KillThread para detener el hilo de ejecución y libre. Antes de que yo en realidad puede destruir el hilo, tengo que estar seguro de que el evento asociado no está en el centro de procesamiento. Si el subproceso fue liberado, mientras que el evento estaba ejecutando una excepción sería debido a que el evento iba a volver a un hilo que ya no existía. He manejado esto con una simple variable Booleana, FOnTimerEventInProgress, que consiguió inicializado en True antes de que el temporizador se ha ejecutado el evento, y pasó a ser Falso justo después de finalizar:



Procedimiento TThreadTimer.KillThread

Begin

& nbsp & nbsp & nbsp Probar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FEnabled := False

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si (FThread <> Nil) A continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // Esperar a la OnTimerInterval Evento

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // acabado antes de terminar el hilo.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Mientras FThread.FOnTimerEventInProgress

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empiezan

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicación.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread.Terminar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread.Libre

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Finalmente

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread := Nil

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FTimerEventCount := 0

& nbsp & nbsp & nbsp Final

Fin




Debido a que el componente abarca un hilo de un objeto, y el objeto de subproceso tiene que hacer referencia a algunas de las propiedades del componente y métodos, he utilizado el de Crear Constructor de la rosca para capturar una referencia a su dueño:



Constructor TTheThread.Create(AOwner:TThreadTimer)

Begin

& nbsp & nbsp & nbsp FOnTimerEventInProgress := False

& nbsp & nbsp & nbsp // necesitamos para acceder a algunos de los del Propietario

& nbsp & nbsp & nbsp // propiedades del hilo.

& nbsp & nbsp & nbsp FOwner := AOwner

& nbsp & nbsp & nbsp Heredado Crear(Falso)

Fin



El hilo objeto en sí es bastante simple. Se ha de Crear un Constructor,Ejecutar, y un método de OnTimer. El método Execute ejecuta justo después de Crear el Constructor, y permanece activo hasta que el método Execute salidas. He utilizado el Terminado de la propiedad para mantener el hilo vivo hasta que se indique expresamente para salir. Terminada se establece en True cuando el hilo de Terminar método es llamado. En la ejecución del bucle, yo uso un simple Sleep() para pausar el hilo y esperar durante un determinado intervalo de tiempo. Yo uso la Aplicación.ProcessMessages para asegurarse de que el hilo tiene toda la corriente de procesamiento de la información antes de ejecutar el evento de temporizador. He incluido una propiedad en el principal componente llamado SynchronizeEvent. Esto hace que el TThreadTimer se comportan como un estándar TTimer componente, mediante la sincronización de los eventos con los principales VCL hilo:



Procedimiento TTheThread.Ejecutar

Begin

& nbsp & nbsp & nbsp Mientras No Yo.Terminado Empiezan

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicación.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Sueño(FOwner.Intervalo)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicación.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FOwner.SynchronizeEvent, a Continuación,

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Sincronizar(OnTimer)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Else

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp OnTimer

& nbsp & nbsp & nbsp Final

Fin



Procedimiento TTheThread.OnTimer

Begin

& nbsp & nbsp & nbsp Probar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si se ha Asignado(FOwner.FOnTimerInterval), a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FOwner.Habilitado, a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOnTimerEventInProgress := True

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Inc(FOwner.FTimerEventCount)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOwner.FOnTimerInterval(FOwner)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Finalmente

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOnTimerEventInProgress := False

& nbsp & nbsp & nbsp Final

Fin



Hay tres piezas esenciales para la TThreadTimer componente: el Hilo, de Intervalo y de la TimerEvent. Como se mencionó anteriormente, el tema es creado y destruido por la propiedad Enabled. Tan pronto como el hilo es creado, el temporizador se activa y ejecuta el OnTimerInterval evento después de que el intervalo de tiempo especificado período transcurrido.



también Hay una función llamada TimerEventCount-hace exactamente lo que su nombre implica. Se incrementa un número entero cada vez que el OnTimerInterval evento se procesa. Esto puede usarse para observar los posibles tiempos de espera. Por ejemplo, usted podría tener el conjunto de intervalo de 1.000 (un segundo), y el evento trampa para TimerEventCount >= 60. Así que si el evento se ejecuta 60 veces, luego de un minuto se ha ido y usted puede ser que necesite para manejar algo en la aplicación. Pero recuerde, este temporizador está en un hilo separado, así que tratando de manipular a otros VCL objetos en el hilo principal, podría resultar en excepciones.



Después de la creación de la ThreadTimer objeto, no pasó mucho tiempo para darse cuenta de que el evento de temporizador sería incapaz de actualizar cualquier VCL objetos, mientras que el hilo principal estaba ocupado. Por ejemplo, si usted querido comprobar un puntero de registro de una tabla, mientras que la tabla estaba siendo procesado y visualización de los resultados a un TLabel, que iba a estar fuera de suerte. TLabel tendrían que esperar hasta que el hilo principal permitido la actualización. Así que de vuelta a la proverbial tablero de dibujo, una vez más.



descubrí que TCanvas, para la mayor parte, no usar el hilo principal para la actualización. Así que he creado una nueva etiqueta de componente llamado TCanvasLabel. TCanvasLabel es una subclase de TGraphicControl, y sólo se utiliza en el Lienzo de la propiedad para el dibujo.



he diseñado TCanvasLabel así que podría ser utilizado como una Etiqueta y un ProgressBar. Las propiedades de Relleno, FillPercent, y el color de Relleno se utilizan para pintar una parte de la etiqueta de la lona de un color diferente. El método Paint se utiliza para mostrar el contenido de la etiqueta:



Procedimiento TCanvasLabel.Pintura

Var

& nbsp & nbsp & nbsp Rect : TRect

& nbsp & nbsp & nbsp fLeft,fTop : Integer

Begin

& nbsp & nbsp & nbsp // AutoSize se debe establecer a False cuando la etiqueta

& nbsp & nbsp & nbsp // se utiliza en un hilo distinto al principal

& nbsp & nbsp & nbsp // VCL hilo.

& nbsp & nbsp & nbsp Si AutoSize, a Continuación,

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp SetSize



& nbsp & nbsp & nbsp Rect := ClientRect

& nbsp & nbsp & nbsp // la etiqueta de la Pintura con el principal color de fondo.

& nbsp & nbsp & nbsp Lienzo.Cepillo.Estilo := bsSolid

& nbsp & nbsp & nbsp Lienzo.Cepillo.Color := Auto.Color

& nbsp & nbsp & nbsp Lienzo.FillRect(ClientRect)



& nbsp & nbsp & nbsp Si (FillPercent > 0) Y FFill, a Continuación, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // calcular el porcentaje de relleno.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Rect.Derecha := Trunc((Rect.Derecho *

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp (FillPercent / 100)))

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.Cepillo.Color := color de Relleno

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.FillRect(Rect)

& nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Lienzo.Cepillo.Estilo := bsClear



& nbsp & nbsp & nbsp Caso de la Alineación De

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taLeftJustify:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taRightJustify:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := ClientRect.Derecho -

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextWidth(Título)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taCenter:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := Trunc((ClientRect.Derecho -

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextWidth(Título))/2)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp Caso de Diseño De

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlTop: fTop := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlCenter:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fTop := Trunc((ClientRect.Abajo

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextHeight(Título))/2)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlBottom:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fTop := (Self.De altura

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextHeight(Título))



& nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Lienzo.TextOut(fleft,fTop,Título)

& nbsp & nbsp & nbsp // la fuerza de la lona para la actualización de sí mismo.

& nbsp & nbsp & nbsp Lienzo.Actualización

Fin



Hay un par de advertencias que usted necesita mirar hacia fuera para cuando el uso de eventos que usar los hilos:



  • La propiedad AutoSize de TCanvasLabel debe ser establecida en False cuando se ejecuta la aplicación. Cambiar el tamaño de la etiqueta utiliza el principal VCL hilo, por lo que la etiqueta no se actualizará.


  • asegúrese de no incluir ningún estándar de CLASIFICACIÓN de los objetos en el hilo de eventos sin fondo, prueba de ellos, o, más específicamente, la creación de ellos en el código dentro de la rosca.





Un simple uso de estos dos componentes se pueden encontrar en la demostración que se incluye en el siguiente archivo. La simple aplicación de muestra

la diferencia entre un estándar TTimer y el temporizador se encuentra en la TThreadTimer componente.



La TTimer actualizaciones de los eventos de un TLabel con la hora actual, una vez cada segundo. Para crear un largo proceso, la aplicación anexa 10.000 registros en un bucle For.







Te darás cuenta de que durante el proceso de anexar, la pantalla de tiempo se detiene para el estándar TTimer, mientras que el resto de las etiquetas se actualizan en sus intervalos designados.

& nbsp







De multiples subprocesos temporizadores


De multiples subprocesos temporizadores : Multi-millones de consejos para hacer su vida mas facil.


Nunca añadido un TTimer para su aplicacion solo para encontrar que su caso no se ejecuta porque el principal VCL hilo esta ocupado?

Desarrolladores de Delphi septiembre de 2000
Copyright de Pinnacle Publishing, Inc. Todos los derechos reservados.el Real Temporizador por Favor, Ejecute?

Steve Zimmelman



la Necesidad es a menudo la madre de la invencion, y esta vez no fue la excepcion. Mientras yo estaba trabajando en algunas de Microsoft Word/Excel integracion, surge un problema cuando yo era procesamiento de documentos con la propiedad Visible en False. Word mostrara un cuadro de dialogo (que el usuario no pueda ver) y esperar una respuesta. Bueno, no hace falta decir que esto hizo que la aplicacion aparezca como si se colgaba. Necesitaba una forma de tiempo en el proceso y manejar las cosas, en caso de tomar demasiado tiempo. Asi que me golpeo un TTimer componente en el formulario, establezca el intervalo de 1.000 (un segundo), y se conto el numero de veces que el evento de temporizador se ejecuta. Suena bien, ¿verdad? Mal! Cuando el cuadro de dialogo de Word se mostro a si misma, fue el uso de los principales VCL hilo, que a su vez no estaba dando paso a otros procesos, incluyendo TTimer. Asi, una vez mas, la aplicacion aparecio como si se colgo.



La solucion fue crear un hilo que podria controlar el tiempo, no importa lo ocupado que el principal VCL hilo. Pero la creacion de un hilo cada vez que he necesitado esta funcionalidad no parece la mejor solucion a partir de un objeto-orientado punto de vista. Asi que he creado un nuevo componente Timer que crear y utilizar su propio hilo de rosca interno y ejecutar un metodo de evento en un intervalo de tiempo especifico.



La TThreadTimer componente es el resultado. Se trata de una simple subclase de TComponent que gestiona una rosca interna. El hilo es creado y destruido por el componente. Cuando la propiedad Enabled es Cierto, el hilo es creado, y cuando es Falsa, es destruido. Yo tambien queria asegurarse de que el hilo no se crean en el modo de diseño. Asi que he comprobado la ComponentState antes de ejecutar cualquiera de los metodos:



Procedimiento TThreadTimer.SetEnabled(Valor:Boolean)

Begin

& nbsp & nbsp & nbsp If (Valor <> FEnabled), a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FEnabled := Valor

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // no Crear o Matar el hilo a menos que

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // se ejecuta la aplicacion.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si No (csDesigning En ComponentState)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp, a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FEnabled, a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FTimerEventCount := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread := TTheThread.Create(Self)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp End Else Begin

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp KillThread

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Final

Fin




he utilizado un metodo llamado KillThread para detener el hilo de ejecucion y libre. Antes de que yo en realidad puede destruir el hilo, tengo que estar seguro de que el evento asociado no esta en el centro de procesamiento. Si el subproceso fue liberado, mientras que el evento estaba ejecutando una excepcion seria debido a que el evento iba a volver a un hilo que ya no existia. He manejado esto con una simple variable Booleana, FOnTimerEventInProgress, que consiguio inicializado en True antes de que el temporizador se ha ejecutado el evento, y paso a ser Falso justo despues de finalizar:



Procedimiento TThreadTimer.KillThread

Begin

& nbsp & nbsp & nbsp Probar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FEnabled := False

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si (FThread <> Nil) A continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // Esperar a la OnTimerInterval Evento

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // acabado antes de terminar el hilo.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Mientras FThread.FOnTimerEventInProgress

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empiezan

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicacion.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread.Terminar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread.Libre

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Finalmente

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FThread := Nil

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FTimerEventCount := 0

& nbsp & nbsp & nbsp Final

Fin




Debido a que el componente abarca un hilo de un objeto, y el objeto de subproceso tiene que hacer referencia a algunas de las propiedades del componente y metodos, he utilizado el de Crear Constructor de la rosca para capturar una referencia a su dueño:



Constructor TTheThread.Create(AOwner:TThreadTimer)

Begin

& nbsp & nbsp & nbsp FOnTimerEventInProgress := False

& nbsp & nbsp & nbsp // necesitamos para acceder a algunos de los del Propietario

& nbsp & nbsp & nbsp // propiedades del hilo.

& nbsp & nbsp & nbsp FOwner := AOwner

& nbsp & nbsp & nbsp Heredado Crear(Falso)

Fin



El hilo objeto en si es bastante simple. Se ha de Crear un Constructor,Ejecutar, y un metodo de OnTimer. El metodo Execute ejecuta justo despues de Crear el Constructor, y permanece activo hasta que el metodo Execute salidas. He utilizado el Terminado de la propiedad para mantener el hilo vivo hasta que se indique expresamente para salir. Terminada se establece en True cuando el hilo de Terminar metodo es llamado. En la ejecucion del bucle, yo uso un simple Sleep() para pausar el hilo y esperar durante un determinado intervalo de tiempo. Yo uso la Aplicacion.ProcessMessages para asegurarse de que el hilo tiene toda la corriente de procesamiento de la informacion antes de ejecutar el evento de temporizador. He incluido una propiedad en el principal componente llamado SynchronizeEvent. Esto hace que el TThreadTimer se comportan como un estandar TTimer componente, mediante la sincronizacion de los eventos con los principales VCL hilo:



Procedimiento TTheThread.Ejecutar

Begin

& nbsp & nbsp & nbsp Mientras No Yo.Terminado Empiezan

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicacion.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Sueño(FOwner.Intervalo)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Aplicacion.ProcessMessages

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FOwner.SynchronizeEvent, a Continuacion,

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Sincronizar(OnTimer)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Else

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp OnTimer

& nbsp & nbsp & nbsp Final

Fin



Procedimiento TTheThread.OnTimer

Begin

& nbsp & nbsp & nbsp Probar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si se ha Asignado(FOwner.FOnTimerInterval), a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Si FOwner.Habilitado, a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOnTimerEventInProgress := True

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Inc(FOwner.FTimerEventCount)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOwner.FOnTimerInterval(FOwner)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Finalmente

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FOnTimerEventInProgress := False

& nbsp & nbsp & nbsp Final

Fin



Hay tres piezas esenciales para la TThreadTimer componente: el Hilo, de Intervalo y de la TimerEvent. Como se menciono anteriormente, el tema es creado y destruido por la propiedad Enabled. Tan pronto como el hilo es creado, el temporizador se activa y ejecuta el OnTimerInterval evento despues de que el intervalo de tiempo especificado periodo transcurrido.



tambien Hay una funcion llamada TimerEventCount-hace exactamente lo que su nombre implica. Se incrementa un numero entero cada vez que el OnTimerInterval evento se procesa. Esto puede usarse para observar los posibles tiempos de espera. Por ejemplo, usted podria tener el conjunto de intervalo de 1.000 (un segundo), y el evento trampa para TimerEventCount >= 60. Asi que si el evento se ejecuta 60 veces, luego de un minuto se ha ido y usted puede ser que necesite para manejar algo en la aplicacion. Pero recuerde, este temporizador esta en un hilo separado, asi que tratando de manipular a otros VCL objetos en el hilo principal, podria resultar en excepciones.



Despues de la creacion de la ThreadTimer objeto, no paso mucho tiempo para darse cuenta de que el evento de temporizador seria incapaz de actualizar cualquier VCL objetos, mientras que el hilo principal estaba ocupado. Por ejemplo, si usted querido comprobar un puntero de registro de una tabla, mientras que la tabla estaba siendo procesado y visualizacion de los resultados a un TLabel, que iba a estar fuera de suerte. TLabel tendrian que esperar hasta que el hilo principal permitido la actualizacion. Asi que de vuelta a la proverbial tablero de dibujo, una vez mas.



descubri que TCanvas, para la mayor parte, no usar el hilo principal para la actualizacion. Asi que he creado una nueva etiqueta de componente llamado TCanvasLabel. TCanvasLabel es una subclase de TGraphicControl, y solo se utiliza en el Lienzo de la propiedad para el dibujo.



he diseñado TCanvasLabel asi que podria ser utilizado como una Etiqueta y un ProgressBar. Las propiedades de Relleno, FillPercent, y el color de Relleno se utilizan para pintar una parte de la etiqueta de la lona de un color diferente. El metodo Paint se utiliza para mostrar el contenido de la etiqueta:



Procedimiento TCanvasLabel.Pintura

Var

& nbsp & nbsp & nbsp Rect : TRect

& nbsp & nbsp & nbsp fLeft,fTop : Integer

Begin

& nbsp & nbsp & nbsp // AutoSize se debe establecer a False cuando la etiqueta

& nbsp & nbsp & nbsp // se utiliza en un hilo distinto al principal

& nbsp & nbsp & nbsp // VCL hilo.

& nbsp & nbsp & nbsp Si AutoSize, a Continuacion,

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp SetSize



& nbsp & nbsp & nbsp Rect := ClientRect

& nbsp & nbsp & nbsp // la etiqueta de la Pintura con el principal color de fondo.

& nbsp & nbsp & nbsp Lienzo.Cepillo.Estilo := bsSolid

& nbsp & nbsp & nbsp Lienzo.Cepillo.Color := Auto.Color

& nbsp & nbsp & nbsp Lienzo.FillRect(ClientRect)



& nbsp & nbsp & nbsp Si (FillPercent > 0) Y FFill, a Continuacion, Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp // calcular el porcentaje de relleno.

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Rect.Derecha := Trunc((Rect.Derecho *

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp (FillPercent / 100)))

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.Cepillo.Color := color de Relleno

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.FillRect(Rect)

& nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Lienzo.Cepillo.Estilo := bsClear



& nbsp & nbsp & nbsp Caso de la Alineacion De

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taLeftJustify:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taRightJustify:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := ClientRect.Derecho -

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextWidth(Titulo)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp taCenter:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Empezar

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fLeft := Trunc((ClientRect.Derecho -

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextWidth(Titulo))/2)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Final



& nbsp & nbsp & nbsp Caso de Diseño De

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlTop: fTop := 0

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlCenter:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fTop := Trunc((ClientRect.Abajo

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextHeight(Titulo))/2)

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp tlBottom:

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp fTop := (Self.De altura

& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Lienzo.TextHeight(Titulo))



& nbsp & nbsp & nbsp Final

& nbsp & nbsp & nbsp Lienzo.TextOut(fleft,fTop,Titulo)

& nbsp & nbsp & nbsp // la fuerza de la lona para la actualizacion de si mismo.

& nbsp & nbsp & nbsp Lienzo.Actualizacion

Fin



Hay un par de advertencias que usted necesita mirar hacia fuera para cuando el uso de eventos que usar los hilos:



  • La propiedad AutoSize de TCanvasLabel debe ser establecida en False cuando se ejecuta la aplicacion. Cambiar el tamaño de la etiqueta utiliza el principal VCL hilo, por lo que la etiqueta no se actualizara.


  • asegurese de no incluir ningun estandar de CLASIFICACION de los objetos en el hilo de eventos sin fondo, prueba de ellos, o, mas especificamente, la creacion de ellos en el codigo dentro de la rosca.





Un simple uso de estos dos componentes se pueden encontrar en la demostracion que se incluye en el siguiente archivo. La simple aplicacion de muestra

la diferencia entre un estandar TTimer y el temporizador se encuentra en la TThreadTimer componente.



La TTimer actualizaciones de los eventos de un TLabel con la hora actual, una vez cada segundo. Para crear un largo proceso, la aplicacion anexa 10.000 registros en un bucle For.







Te daras cuenta de que durante el proceso de anexar, la pantalla de tiempo se detiene para el estandar TTimer, mientras que el resto de las etiquetas se actualizan en sus intervalos designados.

& nbsp

De múltiples subprocesos temporizadores

De múltiples subprocesos temporizadores : Multi-millones de consejos para hacer su vida más fácil.
Recommander aux amis
  • gplus
  • pinterest

Comentario

Dejar un comentario

Clasificación