Diseñando formularios con Python y Kivy

⦿formulario, python, kivy, kivyforms
form

Existen muchas librerías para crear interfaces gráficas con Python. Por poner algún ejemplo, he probado con wxPython, PyQt y Kivy. Esta última es la que más me ha gustado por una serie de razones:

  • Es multiplataforma y funciona en GNU/Linux, Windows, OS X, Android, iOS y Raspberry Pi. Solo he probado las dos primeras pero sí que he podido comprobar que está pensada para usar con teclado y ratón o con pantallas táctiles.
  • No se basa en los widgets nativos de las plataformas sino que tiene los suyos propios, por lo que las aplicaciones se ven igual en todas las plataformas.
  • Es rápida; el motor gráfico funciona sobre OpenGL ES 2 y muchas partes están escritas en Cython.
  • Puedes diseñar las interfaces directamente desde Python o usando el lenguaje Kv.
  • Es un proyecto relativamente nuevo y con un buen mantenimiento.
  • Buena documentación y con muchos ejemplos.

Estoy trabajando en un framework de desarrollo de aplicaciones, por lo que necesito que los desarrolladores puedan diseñar formularios rápidamente, al estilo WYSIWYG, y que además puedan incluir sus propios temas, colores, etc. El hecho de que exista el lenguaje Kv me facilita mucho la tarea. Es algo parecido al QML que tiene Qt y que permite guardar tus composiciones en ficheros de texto que pueden ser cargados despues por la aplicación sin tener que tocar nada de código.

Por ejemplo, el Hello World de Kivy se podría escribir así:

    # main.py file
    from kivy.app import App

    class TestApp(App):
        pass

    TestApp().run()

    # test.kv file
    Button:
        text: 'Hello World'
  

Para diseñar los formularios he creado un widget que proporciona un canvas en el que es posible añadir botones, etiquetas, campos de texto y cosas por el estilo. El proyecto se llama KivyForms y de momento es beta. También podeis ver un vídeo con ejemplo de uso de KivyForms. La idea es que el widget tenga una API potente para poder ser integrado en cualquier aplicación que necesite composición de formularios.

Mirad lo que contiene el widget:

    class FormCanvas(BoxLayout):
        def __init__(self, *args, **kwargs):
            super(FormCanvas, self).__init__(*args, **kwargs)

            self._canvas = StackLayout(
                orientation='lr-tb',
                padding=[10, 10, 10, 10],
                spacing=[10, 10]
            )
            super(FormCanvas, self).add_widget(self._canvas)
  

El FormCanvas se basa en un BoxLayout de Kivy e internamente tiene un StackLayout que es donde realmente se añadirán los widgets del formulario. El StackLayout permite que los demás widgets se vayan apilando sin ocupar todo el tamaño de la pantalla.

    def add_widget(self, widget):
        g = Grabbable(
            height=self.widgets_height,
            size_hint=self.widgets_size_hint
        )
        g.add_widget(widget)
        self._canvas.add_widget(g)
  

Cada vez que añadimos un widget se instancia un elemento Grabbable que contendrá al widget que queremos añadir. Es este elemento Grabbable el que realmente añadimos al canvas. Esto nos permitirá seleccionar el widget y moverlo por el formulario para diseñar la composición.

Existe un elemento Destination que sirve para indicar dónde caera el widget al finalizar la operación de arrastrar.

    class Destination(Label):
        def __init__(self, **kwargs):
            super(Destination, self).__init__(**kwargs)
            self.text = 'Widget goes here'
            self.color = [1, 1, 0, 1]
            with self.canvas.after:
                Color(1, 1, 0, 1)
                self.box = Line(dash_length=8, dash_offset=4)

        def update_box(self):
            self.box.points = [
                self.x, self.y,
                self.x, self.y + self.height,
                self.x + self.width, self.y + self.height,
                self.x + self.width, self.y,
                self.x, self.y
            ]
  

Este elemento, que es una simple etiqueta con el borde punteado, es muy útil para que el desarrollador pueda ubicar los widgets en el lugar adecuado.

Por último, es posible exportar la composición a lenguaje Kv. KivyForms se encarga de eliminar los elementos Grabbable y todo el resto de la configuración necesaria para el diseño del formulario, de forma que es posible guardar la composición directamente a un fichero, lista para ser usada en nuestros programas.

KivyForms se distribuye bajo licencia MIT. Aunque prefiero las licencias GPL, en este caso he decidido usar, por coherencia, la misma licencia que Kivy, así que estais invitados a colaborar en el proyecto.