11. Interfaces visuales

11.1. Abeille

El programa Abeille lo usaremos para la creación de las interfaces visuales. En este programa podremos establecer el aspecto de las ventanas, nombres, etc. Haciendo uso de la librería FormPanel podremos cargarlo fácilmente en un script, y sacarle el máximo partido.

Abriremos el Abeille desde el botón abeille situado en la barra de Herramientas del Scripting Composer.

Nota

Recordar que para que aparezca la herramienta de Abeille, debemos de tener instaladas las herramientas denominadas ScriptingComposerTools que podrás descargar desde el Administrador de Complementos.

Aparece en la imagen el programa Abeille con el ejemplo de coordenadas.xml abierto:

../../../_images/abeille.png

11.2. Ejemplo de uso

Descargar el ejemplo explicado a continuación: CentrarCoordenadas

../../../_images/abeille_1.png

Para crear una interfaz visual crearemos un nuevo formulario en Abeille.

../../../_images/abeille_2.png

Crearemos una nueva etiqueta label.

../../../_images/abeille_3.png

Presionamos el lugar en el que queremos situarlo en la cuadrícula.

../../../_images/abeille_4.png

Ahora podemos dotarle de nombre a la etiqueta. Este nombre es con el que accederemos al componente desde nuestro script. En este caso, le daremos de nombre lblName.

../../../_images/abeille_5.png

Cambiamos el texto que contendrá esta etiqueta a: Coordenadas

../../../_images/abeille_6.png

Se puede ampliar el rango de ocupación de esta casilla en el formulario para ajustarlo mejor al interfaz que vamos a crear. En este caso queremos que ocupe 3 columnas de nuestro grid, dejando una columna por cada lado para que los componentes que estamos creando no estén juntos al borde de la ventana.

../../../_images/abeille_7.png

Vemos que el espacio que ocupa la etiqueta de Coordenas se ha ampliado. Para la interfaz de este script haremos uso de 5 columnas, 3 para situar los componentes y las otras dos de separación con los bordes. Ya podemos eliminar las columnas que no tenemos planeado utilizar. Para ello hacemos uso del control “Delete Columns”:

../../../_images/abeille_71.png

Vamos a ampliar la anchura de algunas columnas del formulario para una mejor visualización, aunque al final explicaremos otras opciones para que el panel se encargue automáticamente de este ancho y nos aseguremos de una correcta visualización. Para ello, solo tenemos que presionar sobre la columna a modificar y desplazar la señal que aparecerá arriba hacia la derecha:

../../../_images/abeille_72.png

Repetimos el proceso para crear dos etiquetas más denominadas lblX y lblY, con textos de “X: ” e “Y: ” respectivamente. Dejaremos una fila entre cada uno de ellos para una correcta visualización:

../../../_images/abeille_8.png

Ahora crearemos un text field o campo de texto. Este campo permitirá tanto mostrar valores, como permitir al usuario introducirlos:

../../../_images/abeille_9.png

Repetimos el mismo proceso anterior para la creación de dos text fields denominados txtX y txtY.

../../../_images/abeille_10.png

A esta columna en la que se sitúan las cajas de texto, vamos a dotarla de la posibilidad de agrandarse en caso necesario, por ejemplo, si el usuario agranda la ventana. Esta opción ayudará a mantener a la correcta visualización de la interfaz, y nos da la opción de detallar los componentes que permitimos que cambien de tamaño.

Para ello, vamos a seleccionar alguna celda situada en la columna que contiene los componentes de Cajas de Texto, y vamos a ir al menú de arriba Column ‣ Resize: Grow.

../../../_images/abeille_101.png

Vemos como ya la previsualización del formulario ha cambiado, apareciendo más grande haciendo uso de esta columna designada:

../../../_images/abeille_102.png

El siguiente paso es crear espacio para los botones de la aplicación, que en este caso, serán dos. El primer botón destinado a realizar una acción que será la de Centrar: btnCenter, y otro botón destinado a cerrar la aplicación: btnClose.

Para tener mayor libertad de configuración en la posición y tamaño de estos botones, así como de ayudar a una correcta visualización de la interfaz, vamos a hacerlo de la siguiente manera.

Primero vamos a insertar un componente de tipo “Embedded Form”. Esta opción nos permite insertar un formulario dentro de otro.

../../../_images/abeille_103.png

Situaremos el nuevo componente debajo de la última etiqueta, dejando una fila de separación:

../../../_images/abeille_104.png

Nos aparecerá una ventana para indicar qué tamaño de formulario queremos insertar, le indicaremos 4 columnas y 1 fila. De esta forma tendremos espacio para situar los dos botones y dejar separación entre ellos.

../../../_images/abeille_105.png

Dando como resultado algo similar a:

../../../_images/abeille_106.png

Una vez insertado, le indicaremos que ocupe también las siguientes dos columnas, de la misma forma que hicimos con la primera etiqueta Coordenadas, usando Increse Column Span.

../../../_images/abeille_107.png

Dejando una fila de separación para el borde de abajo, podemos eliminar también el resto de filas sobrantes. El resultado será similar al siguiente:

../../../_images/abeille_108.png

Vamos a indicarle que este subformulario se alinea a la derecha de la celda en la que está contenido. Presionamos sobre la celda que contiene el subformulario y a la derecha en Form Properties ‣ Cell ‣ Alignment ‣ Horizontal ‣ RIGHT, quedando como resultado:

../../../_images/abeille_109.png

Ahora ya podemos crear los botones en este subformulario, btnCenter y btnClose. Seleccionamos la opción jButton:

../../../_images/abeille_110.png

Y situamos los dos botones dentro del subformulario:

../../../_images/abeille_111.png

Está la opción de ampliar este subformulario por si nos enfrentamos a un caso más complicado:

../../../_images/abeille_112.png

Aparecerá el formulario en una pestaña diferente:

../../../_images/abeille_113.png

Con esto ya tendremos la interfaz preparada, solo tendremos que guardarla en el mismo directorio del script que estábamos creando con extensión .xml:

../../../_images/abeille_114.png

En cualquier momento podremos realizar cambios en este interfaz abriendo el fichero .xml de nuevo desde el Abeille.

Aquí vemos como responde la aplicación a diferentes tamaños que le vamos dando:

../../../_images/abeille_115.png

Desde código podemos establecer el tamaño que queremos que tenga la ventana con la línea self.setPreferredSize(300,300), quedando algo similar según el script que tengamos a:

from gvsig import *
from gvsig.libs.formpanel import FormPanel

class Panel(FormPanel):
    def __init__(self):
        FormPanel.__init__(self, os.path.join(os.path.dirname(__file__), "ui_basic.xml"))
        self.setPreferredSize(300,300)

def main(*args):
    l = Panel()
    l.showTool("Visual")
    pass

También tenemos muchas más opciones que nos permiten configurar con más detalle la forma de reaccionar de nuestros componentes en la interfaz, como por ejemplo, en el menú de opciones de Columna:

../../../_images/abeille_116.png

11.3. Uso de FormPanel

Para la creación de script visuales nos apoyaremos en la clase FormPanel contenida en gvsig.libs.formpanel. Crearemos una clase nueva que contendrá la funcionalidad de nuestro script y extenderemos desde FormPanel.

Primero vamos a crear una carpeta nueva en la que meter nuestro ejemplo.

../../../_images/abeille_script_1.png

Después, un script en esta carpeta denominado centrar_coordenadas.py.

../../../_images/abeille_script_2.png

Guardaremos el formulario explicado en el apartado anterior en esta carpeta.

Ejemplo básico de la carga de una interfaz en un script:

from gvsig import *
from gvsig.libs.formpanel import FormPanel
import os

class Panel(FormPanel):
    def __init__(self):
        FormPanel.__init__(self, os.path.join(os.path.dirname(__file__), "ui_basic.xml"))

def main(*args):
    l = Panel()
    l.showTool("Visual")
    pass

Nos vamos a basar en esta plantilla para la creación de nuestro script de centrar_coordenadas.py.

Por defecto, en FormPanel viene establecido un método btnClose_click, que servirá para cerrar este script. De esta forma solo tenemos que establecer en Abeille un botón denominado btnClose y ya tendremos un botón programado para el cierre de la aplicación.

Tenemos nuestro módulo listo para ser programado. Tenemos una carpeta que contiene el script y la interfaz que utilizará.

../../../_images/abeille_script_3.png

Seguimos desarrollando las funcionalidades de FormPanel. Una de ellas es el auto enlace con eventos que se producen en los elementos de la interfaz visual. Por ejemplo, si tenemos (en nuestro ejemplo) un botón denominado btnCenter y queremos que reaccione al evento cuando lo presionemos, tan solo deberemos de crear un método en nuestra clase que contenga el nombre del elemento “btnCenter” terminado con el evento que queremos capturar “_click”.

De esta forma no tenemos que preocuparnos de eventos, ya que la propia librería FormPanel nos lo gestionará:

# encoding: utf-8

from gvsig import *
from gvsig.libs.formpanel import FormPanel
import os

class CenterCoordinates(FormPanel):
    def __init__(self):
        FormPanel.__init__(self,
                            os.path.join(os.path.dirname(__file__),
                                        "centrar_coordenadas.xml")
                            )

    def btnCenter_click(self, *args):
        print "Clicked!"

    def btnClose_click(self,*args):
        self.hide()

def main(*args):
    l = CenterCoordinates()
    l.showTool("Centrar Coordenadas")
    pass

Al ejecutar el script nos aparecerá una interfaz similar a esta:

../../../_images/abeille_script_4.png

Y lo que ocurre al presionar el botón Centrar, tal y como hemos programado en el método btnCenter_click, mostrará por consola la palabra Clicked!.

../../../_images/abeille_script_5.png

Si presionamos el botón de Cerrar se cerrará la aplicación, haciendo uso de un método ya implementado en la clase FormPanel, sin necesidad de programarlo nosotros mismos. En el caso de que quisiéramos encargarnos nosotros de esta función, solo tendríamos que sobrescribir el método en nuestra clase, o darle otro nombre al componente de cerrar la aplicación.

Por ejemplo, también podríamos modificar el texto de etiquetas u otros valores de una forma similar a:

self.txtX.setText("Clicked!")
self.txtY.setText("Clicked!")
../../../_images/abeille_script_7.png

Como hemos visto, para acceder a nuestros componentes en el interfaz, lo haremos mediante self. + nombre del componente. Por ejemplo, vamos a implementar en el botón Centrar, que muestre por consola las coordenadas que el usuario escriba en las cajas de texto.

Para ello haremos referencia a los componentes de cajas de texto txtX y txtY que hemos programado en la interfaz:

def btnCenter_click(self, *args):
    x = self.txtX.getText()
    y = self.txtY.getText()
    print "X: ", x, " Y: ", y

Aquí vemos como quedaría:

../../../_images/abeille_script_6.png

Ahora, para cumplir el propósito del script, centrar la vista en unas coordenadas que le establezcamos, solo tenemos que modificar el método btnCenter_click por algo similar a lo siguiente:

# encoding: utf-8

from gvsig import *
from gvsig import geom
from gvsig.libs.formpanel import FormPanel
import os

class CenterCoordinates(FormPanel):
    def __init__(self):
        FormPanel.__init__(self,
                            os.path.join(os.path.dirname(__file__),
                                        "centrar_coordenadas.xml")
                            )

    def btnCenter_click(self, *args):
        x = float(self.txtX.getText())
        y = float(self.txtY.getText())
        point = geom.createPoint2D(x, y)
        currentView().centerView(point.getEnvelope())

    def btnClose_click(self,*args):
        self.hide()

def main(*args):
    l = CenterCoordinates()
    l.showTool("Centrar Coordenadas")
    pass

Dando como resultado algo así:

../../../_images/abeille_script_8.png

Vemos como ha centrado la Vista en las coordenadas que hemos indicado en las cajas de texto.

11.4. Tratar con diferentes componentes

11.4.1. Grupos de RadioButton

Una función del interfaz habitual es la creación de un grupo de RadioButton para permitir la selección entre varias opciones. Por lo general, estas opciones van agrupadas y solo se permite la selección de una de ellas. Estas agrupaciones debemos de hacerlas por código de una forma similar a la siguiente.

Después de generar la interfaz en el método __init__ con FormPanel.__init__(..), tendremos que crear el grupo de botones y añadir uno a uno los que forman parte de la agrupación, por ejemplo:

from javax.swing import ButtonGroup
...
self.btgAnswers = ButtonGroup()
self.btgAnswers.add(self.rdbOption1)
self.btgAnswers.add(self.rdbOption2)

Siendo rdbOption1 y rdbOption2, componentes de tipo RadioButton de la interfaz.

../../../_images/interfaz_rdb.png

11.5. Eventos autoregistrados

Hemos comentado que FormPanel se encarga de enlazar los eventos de los componentes con nuestro script, pero no todos los eventos posibles de cada elemento del interfaz están implementados dentro de FormPanel (pero si necesitas alguno de ellos se podrían añadir o implementar en tu propia clase). Aquí mostramos algunos de estos eventos haciendo referencia a spinners, combobox, etc:

def btnCalcular_click(self, *args):
    self.txtField.setText("Clicked!")
    print "Clicked!"

def chb1_change(self, *args):
    print "Check box!"

def rb1_change(self, *args):
    print "Radio button!"

def cmb1_change(self, *args):
    print "Combobox!"

def sld1_focusGained(self, *args):
    print "Slider!", sld1.getValue()

def spn1_change(self, *args):
    print "Spinner!"

def btnClose_click(self,*args):
    self.hide()