Silicon Island

Categorías:

Archivos:

<Julio 2018
Lu Ma Mi Ju Vi Sa Do
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

Blogs Amigos:

rvr
juanje

Cosas de yo:

Synaptia


Get Firefox!
Use GNOME
Blogalia
Haciendo un widget en python y gtk con cairo.
Leyendo éste tutorial en www.pygtk.org he aprendido ésta semana a hacer un widget con la nueva API de cairo.

Sin embargo en el ejemplo, no se habla de como utilizar los eventos para cambiar el dibujo original y hacer transformaciones, asi que he ido un poco más allá, y de paso genero documentación en castellano del asunto.

NOTA: Para poder ejecutar el código vamos a necesitar la versión 2.8 de pygtk.

Primeros pasos


Lo primero que debemos hacer es importar las librerias que vamos a necesitar:

import gtk
import gtk.gdk
import math


Lo siguiente será crear una nueva clase, que heredará de la clase gtk.DrawingArea (área de dibujado) que es el area que utilizaremos para capturar los eventos y dibujar en ella el resultado de las funciones que utilicemos en cairo, añadiremos también un constructor por defecto:

class SemiCirculo(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)


A continuación añadiremos el prototipo de dos de los métodos que vamos a necesitar, uno de ellos se encargará de llevar a cabo las tareas de dibujado y el otro, será el manejador del evento expose, que es el evento que ocurre cuando se redibuja el widget, por ejemplo al moverlo o al pasar una ventana por encima:

class SemiCirculo(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)
                self.connect("expose-event", self.expose)

        def expose(self, widget, event):
                pass

        def draw(self, context):
                pass



Primera prueba

Ahora ya podemos ejecutar nuestro programa, aunque no hará nada, lo que haremos es crear una función principal donde crearemos una ventana y una instancia de nuestra clase, dicha función será llamada sólo en caso de que se ejecute nuestro fuente como un script:

def main():
        window = gtk.Window()
        semicirculo = SemiCirculo()

        # Añadimos nuestro widget a la ventana
        window.add(semicirculo)
        # Conectamos el evento destroy con la salida del bucle de eventos
        window.connect("destroy", gtk.main_quit)
        # Dibujamos toda la ventana
        window.show_all()

        # Comenzamos el bucle de eventos
        gtk.main()

if __name__ == "__main__":
        main()


El fichero fuente deberia éstar tal que asi: ejemplo_1.py

Lo ejecutamos, y obtenemos el siguiente resultado:

[arc@centauri:~]$ python2.4 ejemplo_1.py



Dibujando
Como vemos, aun no hemos hecho nada interesante, a continuación vamos a dibujar el semicirculo, lo primero será crear la función draw:

       def draw(self, context):
                #Adquirimos las coordenadas de origen
                #y el tamaño del rectangulo del widget,
                #situando en las variable x e y
                #el centro del rectangulo.
                rect = self.get_allocation()
                x = rect.x + rect.width / 2
                y = rect.y + rect.height / 2

                #hallamos el radio
                radius = min(rect.width / 2, rect.height / 2) - 5

                #Dibujamos un arco
                context.arc(x, y, radius, 0,(1 * math.pi))

                #Elegimos el color de relleno y lo vertemos
                context.set_source_rgb(0.7, 0.8, 0.1)
                context.fill_preserve()

                #Elegimos el color del borde y lo dibujamos
                context.set_source_rgb(0, 0, 0)
                context.stroke()


Ahora debemos desarrollar el código del manejador del evento:
       def expose(self, widget, event):
                #Creamos un contexto de dibujo cairo
                self.context = widget.window.cairo_create()

                #Ajustamos el tamaño del contexto al del widget
                self.context.rectangle(event.area.x, event.area.y,
                                event.area.width, event.area.height)
                self.context.clip()

                #Llamamos a la función de dibujado
                self.draw(self.context)
                return False


El ejemplo hasta ahora deberia quedar asi: ejemplo_2.py
Ahora ya tenemos un semicirculo que se redimensiona al mismo tiempo que la ventana:



Creando eventos nuevos

DrawingArea, por defecto, no captura los eventos de pulsación y movimiento del ratón, asi que hay que añadirselos a mano en el constrcutor:

class EggClockFace(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)
                self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
                                gtk.gdk.BUTTON1_MOTION_MASK)


Ahora debemos crear los manejadores de los dos nuevos eventos, como miembros de nuestra clase SemiCirculo:

       def pressing(self, widget, event):
                pass

        def moving(self, widget, event):
                pass


Ahora conectamos los eventos con los nuevos manejadores:

class EggClockFace(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)
                self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
                                gtk.gdk.BUTTON1_MOTION_MASK)

                self.connect("expose_event", self.expose)
                self.connect("button_press_event", self.pressing)
                self.connect("motion_notify_event", self.moving)


Ahora queremos que el semicirculo, tras haber hecho click y sin soltar previamente, se mueva en la misma dirección en la medida que nos desplacemos en el eje X, para ello, el manejador debe guardar la coordenada de referencia, es decir, la posición del ratón cuando se produce el evento button-press (el click izquierdo):

       def pressing(self, widget, event):
                self.pressing_x = event.x


Y ahora el manejador de movimiento:
       def moving(self, widget, event):
                #Determinamos si nos movemos a la izquierda
                #o hacia la derecha
                if (self.pressing_x - event.x) > 1:
                        self.desp = self.desp + 0.1
                else:
                        self.desp = self.desp - 0.1

                self.pressing_x = event.x

                #Volvemos a dibujar el contexto
                self.draw(self.context)
                #Redibujamos el widget
                self.queue_draw()



Ya solo nos falta, determinar un desplazamiento por defecto en el constructor y sumar el desplazamiento en la función que dibuja el arco:
class EggClockFace(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)
                self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
                                gtk.gdk.BUTTON1_MOTION_MASK)

                self.connect("expose_event", self.expose)
                self.connect("button_press_event", self.pressing)
                self.connect("motion_notify_event", self.moving)

                #Desplazamiento
                self.desp = 0





Y por último, modificamos la función que dibuja el arco:

               context.arc(x, y, radius, 0 + self.desp ,
                                (1 * math.pi) + self.desp)


Finalmente el fichero nos quedará asi: ejemplo_3.py


Actualización: Éste tutorial está registrado bajo .

2005-12-22 16:46 | Categoría: | 3 Comentarios | Enlace

Referencias (TrackBacks)

URL de trackback de esta historia http://arclnx.blogalia.com//trackbacks/35920

Comentarios

1
De: Juanje Fecha: 2005-12-23 05:23

plas, plas, plas...

Mola mucho el articulo. Muy interesante a la par que instructivo ;-)

Felicidades. Podrias currarte alguno mas de estos, ¿no? :-P



2
De: arc Fecha: 2005-12-26 23:55

Jo, vale, pero dejame respirar... que no veas el copypaste del html resaltado el trabajo que me llevó ;)



3
De: Rafael Villar Burke Fecha: 2006-01-12 14:23

Si haces una versión estática de esta página (con algo de css) podríamos publicar esto en pygtk.org. Si lo hicieses en inglés y pusieses una licencia libre (mit o artística, por ejemplo), ya sería el colmo...

Ah, y ¡enhorabuena por el artículo!



Nombre
Correo-e
URL
Dirección IP: 54.198.104.202 (01ab5ced2f)
Comentario
¿Cuánto es: diez mil + uno?

© 2002 - 2003 arc
Powered by Blogalia