PyGTK/Smooth Animation with PyGTK/lang-es: Difference between revisions
(10 intermediate revisions by 2 users not shown) | |||
Line 14: | Line 14: | ||
== Eventos PyGTK == |
== Eventos PyGTK == |
||
La cola de eventos de PyGTK es el medio por el cual los eventos como clic de ratón, tecla precionada y notificaciones las envía PyGTK. Los eventos se encolan en una lista que necesitan ser ejecutados. |
|||
The PyGTK event queue is the means by which PyGTK events like mouse clicks, key presses and notifications are dispatched. The event queue is a list of events that need to be executed. Events can be generated by user input, or by other events such as an expose event generated by a window being resized. |
|||
Los eventos pueden ser generados por interacción del usuario, o por otros eventos como puede ser el tamaño inicial de una ventana. |
|||
The typical PyGTK application sequence looks like this: |
|||
La aplicación tipica de PyGTK se ve de esta manera: |
|||
* Create GTK windows and widgets. |
|||
* Connect events to functions. |
|||
⚫ | |||
* Crea una ventana y widgets GTK. |
|||
The gtk.main() function simply processes the event queue, dispatching events to the connected functions, until the gtk.main_quit() is called, at which point it returns and the application usually exits. Note that in Sugar Activities, gtk.main() is called for you by the sugar-activity launcher script. |
|||
* Conecta los eventos a las funciones. |
|||
⚫ | |||
La función gtk.main() simplemente procesa la cola de eventos, despachando eventos conectados a la funciones, hasta que gtk.main_quit() es llamada, al punto que regresa a la aplicacion exsitente. Nota que en las actividades de Sugar, gtk.main() es llamado por la actividad de sugar por un script al ser ejecutada. |
|||
This event-driven system is good for GUI applications which typically want to be idle until some external event (such as user input) occurs. But for realtime applications, you generally want some piece of code executing all the time. Fortunately, there are several ways to achieve this kind of regular processing in PyGTK. |
|||
Este sistema manejado por eventos es bueno para las aplicaciones de GUI las cuales tipicamente quieren estar en espera que un evento externo (como la acción de un usurario) ocurra. Pero para aplicaciones en tiempo real, generalmente quieres un poco de codigo ejecutandose todo el tiempo. Afortunadamente, existen diferentes maneras de alcanzar este tipo de procesos en Pygtk. |
|||
⚫ | |||
⚫ | |||
Using gobject.timeout_add(ms, fn) you can cause PyGTK to call a specific function every N milliseconds. This is most people's first approach to smooth animation. |
|||
Usando gobject.timeout_add(ms, fn) tu puedes hacer en PyGTK llamadas especifcas a la funcion cada N milisegundos. Esto suele ser el primer paso suave de acercamiento a la animación. |
|||
Un problema con el evento de reloj es que el reloj solo se inicia cuando retorna *después* de la función. De este modo si el reloj se establece hasta 30ms y la funcion se ejecuta despues de los 20ms, eso puede estar llamando 50ms despues del primer llamado. Por lo tanto, el ritmo o la sincronización se convierte un poco inconsistente a menos que en la función simpre se tome exactamente la misma cantidad de tiempo (y el costo de la funcion necesariamente este tomado encuenta en el tiempo de espera) |
|||
One problem with timer events is that the timer only starts counting again *after* the function returns. So, if the timer is set to 30ms and your function takes 20ms to execute, it will be called 50ms after it was first called. Therefore, the timing becomes inconsistent unless your function always takes exactly the same amount of time (and the cost of your function must be accounted for when choosing the timeout). |
|||
Un segundo problema esta en que si no se cuenta con los milisegundos suficientes para todos los eventos a ser procesdaso sobre el evento del reloj, puedes perder la secuencia de los eventos (o la cola de estos)de tal manera que no se ejecute ninguno. Esto puede causar que el programa tiemble, la GUI falla al momento de actualizar, entre otros problemas. |
|||
A second problem is that if the millisecond count not enough for all other events to be processed between timer events, you can starve the event queue in such a way that other events will never happen. This can cause the program to stutter, the GUI to fail to update, and numerous other problems. |
|||
Nota. Cuando la animación este finalizada, tu puedes detener el evento de reloj para retornar False desde el encabezado de la función. |
|||
Note that when the animation has finished, you can stop the timer event by returning False from your handler function. |
|||
==== Ejemplo ==== |
==== Ejemplo ==== |
||
Line 40: | Line 41: | ||
class MyActivity(Activity) |
class MyActivity(Activity) |
||
def __init__(self): |
def __init__(self): |
||
# |
# Agrega unos 20fps (50ms) tiempo de animacion. |
||
gobject.timeout_add(50, self.timer_cb) |
gobject.timeout_add(50, self.timer_cb) |
||
def timer_cb(self): |
def timer_cb(self): |
||
# |
# Generando un evento de apertura |
||
self.queue_draw() |
self.queue_draw() |
||
return True |
return True |
||
Line 50: | Line 51: | ||
== Eventos Idle == |
== Eventos Idle == |
||
Usando gobject.idle_add(fn) puedes configurar funciones que se llamaran cada vez que PyGTK esta en espera, eso es cuando no hay otros eventos para procesar. |
|||
Esto puede mejorar con el tiempo desde que facilita que los eventos no se manejaran, y otros eventos como comandos y actualiaciones de la GUI se ejecutran antes que la función sea llamada. |
|||
This can be an improvement over timer events since it ensures that the event queue will not be starved, and other events like input and GUI updates will execute before your function is called. |
|||
El problema con esto que otros eventos (como movimientos del mouse) tomen prioridades sobre eventos en espera, o vice versa, el cual lleva a la animacion se retrase ya que los eventos externos o otros procesos retrazaran el proceso de animación. |
|||
The downside is that other events (like mouse movement) take priority over your idle event, or vice versa, which leads to animation stuttering when lots of external events happen, or else delays in processing external events while animation is running. |
|||
Como los eventos del timer, puede parar el evento en espera de ser generados regresando un '''False''' de la función que lo maneja. |
|||
Like timer events, you can stop the idle event from being generated by returning False from your handler function. |
|||
==== Ejemplo ==== |
==== Ejemplo ==== |
||
Line 69: | Line 70: | ||
return True |
return True |
||
== |
== Hilos | SubProcesos == |
||
Apesar de todo, otra opcion para la animación es la creación de un hilo secundario o subproceso que repetidas veces llamará queue_draw o alguna otra funcion a actualizar los gráficos. |
|||
Yet another option for animation is to create a secondary thread which repeatedly calls queue_draw or some other function to update graphics. |
|||
Esto es cuando se trabaja con PyGame, pero en mi experiencia el evento de hacer colas o encolar tiende a llenar hasta desbordar por completo la animacion y la aplicación deja de responder. |
|||
This is how PyGame works, but in my experience the event queue tends to fill up leading to jerky animation and an unresponsive application. |
This is how PyGame works, but in my experience the event queue tends to fill up leading to jerky animation and an unresponsive application. |
||
Donde el XO solamente tiene un solo procesador, multihilo agrega adicionalmente una sobrecarga al sistema y tendrías que lidiar con la carga extra de GTK Python y con los gastos generales de la sincronización. |
|||
Since the XO only has a single processor, multithreading adds additional overhead to the system, and you will have to deal with extra GTK and Python synchronization overhead as well. |
|||
==== Example ==== |
==== Example ==== |
||
Line 96: | Line 99: | ||
== Tomando control del evento de bucle == |
== Tomando control del evento de bucle == |
||
El último método, y el único que he encontrado que es lo suficientemente confiable para los juegos, es hacerse cargo de el ciclo de eventos PyGTK. Esto es lo que SDL hace internamente, y es el patrón por el cual la mayoría de los juegos de Windows funcionan así. |
|||
The last method, and the only one I have found that is reliable enough for games, is to take over the PyGTK event loop. This is what SDL does internally, and is the pattern by which most Windows games operate as well. |
|||
La función gtk.main() soporta llamadas recursivas, y tiene una función gtk.main_iteration()con procesos de eventos simples y retornos. La pieza final del rompecabeza es gtk.events_pending(), que retorna Verdadero si existen eventos pendientes. |
|||
Este método es el mas seguro, ya que sabe que va a obtener todo el tiempo disponible, pero también que todos los eventos de GTK serán procesadas tan pronto como sea posible. |
|||
The gtk.main() function supports being called recursively, and it has a gtk.main_iteration() function which processes a single event and returns. The final piece of the puzzle is gtk.events_pending(), which returns True if any events are pending. |
|||
This method is the most reliable, since you know that you will get all the available time, but also that all GTK events will be processed as soon as possible. |
|||
==== Ejemplo ==== |
==== Ejemplo ==== |
||
Line 119: | Line 123: | ||
== Exponer eventos versus dibujo Inmediato == |
== Exponer eventos versus dibujo Inmediato == |
||
En el ejemplo anterior, se ha llamado a self.queue_draw() para generar un evento que provoca que se actualice toda la pantalla. Es una actividad real, solo que se desa actualizar cualquier widget o sección de la animación. |
|||
Sin embargo, otra opción es ejecutar los comandos del dibujo (usuando cairo, gtk.Drawable, etc) en el ciclo principal. Esto no es penalizado, así que sería bueno considerar en las aplicaciones como juegos donde se mezcla lógica de representación con el código de actualización. |
|||
== Ejemplo del mundo real == |
== Ejemplo del mundo real == |
||
Para un ejemplo que el juego escrito completamente en PyGTK usando estas tecnicas en la practica, ver la actividad [[ThreeDPong]]. |
|||
[[Category:Developers]] |
[[Category:Developers]] |
Latest revision as of 10:29, 15 July 2011
Traducción de PyGTK/Smooth_Animation_with_PyGTK | original |
english | español +/- | cambios |
Esta página describe las diferentes formas de tener una animación suave en PyGTK, con varios pros y contras.
Vida de la batería
Es importante entender que agregando animaciones contstantes (por ejemplo animar el fondo) hara que la laptop no entre en modo de suspención y hara que la batería se consuma rápidamente, haciendo tu aplicación menos popular en el mundo real.
Así que solo debes usar actividades animadas cuando sean absolutamente necesario, y por la cantidad de tiempo mas corta posible.
Eventos PyGTK
La cola de eventos de PyGTK es el medio por el cual los eventos como clic de ratón, tecla precionada y notificaciones las envía PyGTK. Los eventos se encolan en una lista que necesitan ser ejecutados.
Los eventos pueden ser generados por interacción del usuario, o por otros eventos como puede ser el tamaño inicial de una ventana.
La aplicación tipica de PyGTK se ve de esta manera:
- Crea una ventana y widgets GTK.
- Conecta los eventos a las funciones.
- Llama a gtk.main().
La función gtk.main() simplemente procesa la cola de eventos, despachando eventos conectados a la funciones, hasta que gtk.main_quit() es llamada, al punto que regresa a la aplicacion exsitente. Nota que en las actividades de Sugar, gtk.main() es llamado por la actividad de sugar por un script al ser ejecutada.
Este sistema manejado por eventos es bueno para las aplicaciones de GUI las cuales tipicamente quieren estar en espera que un evento externo (como la acción de un usurario) ocurra. Pero para aplicaciones en tiempo real, generalmente quieres un poco de codigo ejecutandose todo el tiempo. Afortunadamente, existen diferentes maneras de alcanzar este tipo de procesos en Pygtk.
Eventos de Tiempo
Usando gobject.timeout_add(ms, fn) tu puedes hacer en PyGTK llamadas especifcas a la funcion cada N milisegundos. Esto suele ser el primer paso suave de acercamiento a la animación.
Un problema con el evento de reloj es que el reloj solo se inicia cuando retorna *después* de la función. De este modo si el reloj se establece hasta 30ms y la funcion se ejecuta despues de los 20ms, eso puede estar llamando 50ms despues del primer llamado. Por lo tanto, el ritmo o la sincronización se convierte un poco inconsistente a menos que en la función simpre se tome exactamente la misma cantidad de tiempo (y el costo de la funcion necesariamente este tomado encuenta en el tiempo de espera)
Un segundo problema esta en que si no se cuenta con los milisegundos suficientes para todos los eventos a ser procesdaso sobre el evento del reloj, puedes perder la secuencia de los eventos (o la cola de estos)de tal manera que no se ejecute ninguno. Esto puede causar que el programa tiemble, la GUI falla al momento de actualizar, entre otros problemas.
Nota. Cuando la animación este finalizada, tu puedes detener el evento de reloj para retornar False desde el encabezado de la función.
Ejemplo
class MyActivity(Activity) def __init__(self): # Agrega unos 20fps (50ms) tiempo de animacion. gobject.timeout_add(50, self.timer_cb) def timer_cb(self): # Generando un evento de apertura self.queue_draw() return True
Eventos Idle
Usando gobject.idle_add(fn) puedes configurar funciones que se llamaran cada vez que PyGTK esta en espera, eso es cuando no hay otros eventos para procesar.
Esto puede mejorar con el tiempo desde que facilita que los eventos no se manejaran, y otros eventos como comandos y actualiaciones de la GUI se ejecutran antes que la función sea llamada.
El problema con esto que otros eventos (como movimientos del mouse) tomen prioridades sobre eventos en espera, o vice versa, el cual lleva a la animacion se retrase ya que los eventos externos o otros procesos retrazaran el proceso de animación.
Como los eventos del timer, puede parar el evento en espera de ser generados regresando un False de la función que lo maneja.
Ejemplo
class MyActivity(Activity) def __init__(self): gobject.idle_add(50, self.idle_cb) def idle_cb(self): # Generate an expose event. self.queue_draw() return True
Hilos | SubProcesos
Apesar de todo, otra opcion para la animación es la creación de un hilo secundario o subproceso que repetidas veces llamará queue_draw o alguna otra funcion a actualizar los gráficos.
Esto es cuando se trabaja con PyGame, pero en mi experiencia el evento de hacer colas o encolar tiende a llenar hasta desbordar por completo la animacion y la aplicación deja de responder.
This is how PyGame works, but in my experience the event queue tends to fill up leading to jerky animation and an unresponsive application.
Donde el XO solamente tiene un solo procesador, multihilo agrega adicionalmente una sobrecarga al sistema y tendrías que lidiar con la carga extra de GTK Python y con los gastos generales de la sincronización.
Example
# Do not forget this! Without it, you will get random crashes. It must be called before gtk.main(). gtk.gdk.threads_init() class MyActivity(Activity) def __init__(self): thr = threading.Thread(target=self.mainloop) thr.start() def mainloop(self): while True: # Generate an expose event. self.queue_draw() # Allow the main thread to process for a while. time.sleep(10)
Tomando control del evento de bucle
El último método, y el único que he encontrado que es lo suficientemente confiable para los juegos, es hacerse cargo de el ciclo de eventos PyGTK. Esto es lo que SDL hace internamente, y es el patrón por el cual la mayoría de los juegos de Windows funcionan así.
La función gtk.main() soporta llamadas recursivas, y tiene una función gtk.main_iteration()con procesos de eventos simples y retornos. La pieza final del rompecabeza es gtk.events_pending(), que retorna Verdadero si existen eventos pendientes.
Este método es el mas seguro, ya que sabe que va a obtener todo el tiempo disponible, pero también que todos los eventos de GTK serán procesadas tan pronto como sea posible.
Ejemplo
class MyActivity(Activity) def __init__(self): # Start up the main loop just after application initialization. self.timeout_add(20, self.mainloop) def mainloop(self): while True: # Process all pending events. while gtk.events_pending(): gtk.main_iteration(False) # Generate an expose event (could just draw here as well). self.queue_draw()
Exponer eventos versus dibujo Inmediato
En el ejemplo anterior, se ha llamado a self.queue_draw() para generar un evento que provoca que se actualice toda la pantalla. Es una actividad real, solo que se desa actualizar cualquier widget o sección de la animación.
Sin embargo, otra opción es ejecutar los comandos del dibujo (usuando cairo, gtk.Drawable, etc) en el ciclo principal. Esto no es penalizado, así que sería bueno considerar en las aplicaciones como juegos donde se mezcla lógica de representación con el código de actualización.
Ejemplo del mundo real
Para un ejemplo que el juego escrito completamente en PyGTK usando estas tecnicas en la practica, ver la actividad ThreeDPong.