Esta receta pretende recoger una colección sobre pequeños ‘trucos’ de GTK que siempre viene bien tener a mano.

GtkkTreeview

  • Desactivar los elementos seleccionados: parece intuitivo, pero la primera vez que lo buscas, te vuelves loco. Se debe hacer con un objeto GtkTreeSelection, usando el método unselect_all().
  • Ejemplo


    selection = view.get_selection()
    selection.unselect_all()

GtkIconView

  • Iconos de stock en IconView: resulta que el IconView es un widget un tanto especial, hasta la fecha. Es muy restrictivo en cuando al modelo que le puedes especificar y no permite usar cell_func para renderizar nuestros datos. Además, los iconos deben ser obligatoriamente pixbuf. Por tanto, si lo que tenemos es los nombres de stock de los iconos, debemos convertirlos a pixbuf antes de meterlos en el store del iconview. Para eso, podemos usar el método render_icon de gtk.Widget. Necesita como mínimo dos parámetros, el stock y el tamaño, y retorna un pixbuf listo para meter en el modelo.
  • Ejemplo


    iv = gtk.IconView()
    st = gtk.ListStore(str, gtk.gdk.Pixbuf)
    icon = iv.render_icon(“gtk-file”, gtk.ICON_SIZE_BUTTON)
    st.append([“un fichero”, icon])

GtkTreeStore, GtkListStore

  • Crear el modelo con tuplas o listas: quizá en este caso, lo obvio sería utilizar el tipo tuple o list, pero si lo haces, Gtk te responde con un bonito:

  • TypeError: could not get typecode from object
    

    Así, lo más sencillo es utilizar object de Python, que se acoge a lo que le des :-).

    Ejemplo


    t = gtk.ListStore(str, object)
    t.append([“nums”, (1,2,3,4,5,6,7,8,9,0)])

Nuevos widgets

  • PyGtk: Generalmente, hacer un nuevo widget en PyGtk es muy sencillo. Basta con crear una nueva clase que herede de otro widget y llamar al ‘inicializador’ adecuado, es decir, en nuestro init llamamos a Gtk.WidgetDelQueHeredamos.init(self) y listo.
  • Ejemplo


    class MyTreeStore(gtk.TreeStore):
    def init(self):
    gtk.TreeStore.init(self)

Tamaño de un widget

  • Obtener el tamaño de un widget y su posición: para conseguir esto, el widget ha de estar realized, es decir, ha de haberse llamado a las primitivas para construirlo antes de pintarlo. Si el widget es visible, esto ya ha ocurrido. Si no, es posible utilizar el método realize() para forzarlo. Una vez hecho esto, el objeto tiene su tamaño y sus coordenadas en el atributo allocation, que es un gdk.Rectangle.
  • Ejemplo

    # Tomado de http://faq.pygtk.org/index.py?req=show&file=faq05.009.htp
    win = gtk.Window()
    win.realize() # o win.show()
    rect = win.allocation

Gtk.Events

  • Mejorar el rendimiento: supongamos que tenemos un callback conectado al evento “motion_notify_event”, y que en ese callback dibujamos algo (por ejemplo, usando Cairo). Si el método tarda en dibujar, se encolarán un montón de eventos sin procesar, que se despacharán después de que el usuario haya empezado la sucesión de eventos. Esto provoca, por ejemplo, que al desplazar un elemento, este se mueva siempre por detrás de donde está el ratón, dando una desagradable sensación. Para evitar eso, podemos bloquear la emisión del evento, hasta que se pueda procesar.
  • Ejemplo

    # Callback del evento 'motion_notify_event'
    def on_motion_notify_event(self, widget, event):
        widget.handler_block_by_func(self.on_motion_notify_event)
    
        # Your code goes here
    
        def _unblock():
            widget.handler_unblock_by_func(self.on_motion_notify_event)
        gobject.idle_add(_unblock)
    
        return True

Cairo

  • Redibujar sólo lo necesario: puesto que el evento expose se produce muchas veces, es interesante poder repintar sólo las zonas necesarias. Para ello, usamos clip(), que crea una zona de dibujo, enmascarando los cambios producidos fuera de esta zona.
  • Ejemplo

    1. ctx es el contexto de dibujo de Cairo
      ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
      ctx.clip()
  • Crear una ventana transparente: para poder probar esto, es necesario tener habilitado el compositing en el gestor de ventanas. El truco básicamente consiste en crear una ventana sin decoraciones, y con el colormap adecuado (uno que soporte canales alpha), y pintar sobre ella con cairo.
  • Ejemplo

    #!/usr/bin/env python
    # -*- mode: python; coding: utf-8 -*-
    
    import sys
    import gtk
    import cairo
    
    
    def expose_event(widget, event):
        cr = widget.window.cairo_create()
        size = widget.get_size()
    
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.rectangle(1, 1, size[0]-2, size[1]-2)
    
        cr.set_source_rgba(1, 1, 1, .8)
        cr.stroke_preserve()
    
        cr.set_source_rgba(1, 1, 1, .2)
        cr.fill()
    
    
    def main():
    
        win = gtk.Window()
        win.set_decorated(False)
        win.set_app_paintable(True)
    
        win.connect('delete-event', gtk.main_quit)
        win.connect('expose-event', expose_event)
    
        screen = win.get_screen()
        colormap = screen.get_rgba_colormap()
        win.set_colormap(colormap)
    
        # avoid flick
        win.realize()
        win.window.set_back_pixmap(None, False)
    
        win.show_all()
        gtk.main()
    
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            pass

    Resultado

GtkPixbuf

  • Cargar gdk.Pixbuf desde un buffer: a veces es útil poder renderizar un pixbuf desde datos de un streaming, o desde un socket, en lugar de usar las fuentes comunes de imágenes de gtk (ficheros, stock, etc.). Para ello, es posible usar gdk.PixbufLoader, que nos permite escribir los datos poco a poco, y cuando están todos disponibles, obtener el Pixbuf.
  • Ejemplo


    pbl = gtk.gdk.PixbufLoader()
    pbl.write(data)
    pbl.close()
    pixbuf = pbl.get_pixbuf()

  • Cargar un gdk.Pixbuf desde stock: aunque esto ya lo hemos visto más arriba, formaba parte de otro ejemplo. Aquí lo vemos más claro. Tenemos un Stock ID, y queremos cargar un gdk.Pixbuf a partir de él. Es fácil si usamos gtk.Widget.render_icon(). Te retorna el Pixbuf directamente.
  • Ejemplo

    pixbuf = gtk.Invisible().render_icon(gtk.STOCK_ZOOM_100, gtk.ICON_SIZE_BUTTON)

PD: Se admiten nuevos Tips ’n Tricks :-D

Referencias



blog comments powered by Disqus