Este tutorial intenta proporcionar una guía paso a paso para los desarrolladores de Haskell que quieren escribir aplicaciones GTK+ usando Glade. Asumimos que estás usando Linux aunque tanto el conjunto de herramientas Gtk+, el diseñador de interfaces Glade y Gtk2Hs están disponibles en otras plataformas.
Esta página tutorial es una adaptación para Haskell y Gtk2Hs de un tutorial original para C y la GTK+ C API
Necesitarás:
Crearás una aplicación tipo "Hello World" como esta:
Glade permite al desarrollador un diseño rápido y eficiente de una aplicación visual y entonces concentrarse en la implantación del programa en vez de preocuparse de los problemas del interfaz de usuario.
Inicia Glade. Se abrirá con un nuevo proyecto sin título. Entonces verás lo siguiente. (Pulsa en las imágenes para verlas a tamaño completo) :
La paleta en la izquierda permite añadir widgets a la aplicación, mientras que el panel de propiedades, abajo a la derecha, permite seleccionar las propiedades del widget seleccionado para ser modificado y las señales (lo veremos después) que serán definidas
La primera cosa que vamos a necesitar es un lugar para añadir los widgets, así que vamos a crear una ventana, pulsando en el icono Ventana de la paleta.
icono ventana
Un widget tipo ventana aparecerá en el canvas (espacio de trabajo) preparado para
ser modificado. Fíjate en las propiedades de la ventana (bajo la pestaña General)
en particular que su denominación es window1
Vamos a asignarle un nombre más descriptivo para ser mostrado en la barra de título de la ventana en tiempo de
ejecución.
Escribe Hola Gtk2Hs
el el campo Título.
Perfecto, la ventana está ya preparada, así que vamos a añadir algunos botones y etiquetas... pero espera! Todavía no podemos añadir widgets. Los widgets en GTK+ están empaquetados. Empaquetar widgets puede parecer pesado al principio pero realmente es un método ingenioso para permitir muchas cosas interesantes, la principal de ellas es el resizing (cambio de tamaño de la ventana) automático. Cuando un usuario cambia el tamaño de una aplicación, normalmente queremos que los widgets de la ventana cambien también su tamaño para aprovechar mejor el nuevo espacio, ya sea expandiendose o comprimiendose. El empaquetado permite que esto se haga automáticamente y afortunadamente libera al programador de escribir código de adaptación al nuevo tamaño. El empaquetado se realiza creando cajas o tablas. Estos widgets son invisibles, lo que quiere decir que no se ven en el momento de la ejecución del programa, sin embargo tienen efecto en la aplicación.
Si volvemos a la aplicación que estamos creando, puedes ver que se puede dividir la ventana en tres filas: la etiqueta de arriba, el campo de entrada de texto en el medio y los dos botones de abajo. Así que lo que vamos a hacer es crear un widget VBox (Caja vertical) con tres filas. Pulsa el icono Caja Vertical en la paleta y después pulsa en cualquier lugar de la ventana que acabamos de crear.
icono Caja Vertical
Indica que quieres tres filas y pulsa Aceptar. La ventana queda ahora dividida en tres filas, preparada para añadir más widgets. Añade un widget de etiqueta a la primera fila.(superior)
icono de etiqueta(puede ser diferente a este)
En la segunda fila coloca un widget de entrada de texto.
icono de entrada de texto
La ventana de la aplicación y su correspondiente árbol de widgets debería parecerse a esto:
Antes de poder añadir los botones en la tercera fila, debemos crear una caja horizontal dentro de ella. El nuevo widget caja horizontal debe tener dos columnas, una para cada botón. Esto lo conseguimos pulsando el icono Caja Horizontal de la paleta y pulsando la tercera fila de la ventana.
icono caja horizontal
Indica dos columnas y pulsa Aceptar. La tercera fila se divide ahora horizontalmente en dos secciones iguales.
Quizá sea un buen momento para salvar el proyecto. Por defecto, Glade lo salva como
un fichero .glade
en tu directorio raíz. Nombra el proyecto como
holagtk2hs
.
amos a hacer los botones. Cada una de las secciones que creamos en la tercera fila de la caja vertical alojará un botón, así que añadamos un widget de botón pulsando el icono botón en la paleta y después pulsando en la primera (izquierda) sección. Haz lo mismo para la segunda sección.
icono de botón
Perfecto, así que nuestros botones están en su lugar:
Ahora vamos a cambiar algunas propiedades de empaquetado para mejorar el aspecto y para darle identidad a nuestros botones (recuerda que puedes seleccionar facilmente los widgets desde el panel Inspector) Lo seleccionas en el árbol y modificas las propiedades con el inspector.
hbox1
a Si
hbox1
y
vbox1
a 4
hbox1
and
vbox1
a 4
button1
a
Stock, después cambia la propiedad Stock Button a Aplicar
button2
a
Stock, después cambia la propiedad Stock Button a Cerrar
Lo mejor de desarrollar con Glade es que ves inmediatamente el aspecto que tendrá tu aplicación, así que modifica las propiedades hasta que consigas el aspecto que quieres.
La última propiedad que vamos a cambiar antes de comenzar con el código. Cambia la propiedad
Etiqueta en la pestaña General para label1
a Dime tu nombre:
y salva el proyecto
Si miras ahora en tu directorio principal (o el directorio que hayas elegido para
guardar el proyecto) todo lo que podrás ver es el fichero con la extensión .glade
.
Es un fichero XML y puedes inspeccionarlo con un editor o un navegador.
Si lo haces, verás cada widget que has especificado como un elemento XML, cada uno
con un atributo id
. Este nombre único, en nuestro caso asignado por defecto
por Glade es el que usará Gtk2Hs para acceder a los widgets (como puedes ver en //Listado
de código A// más abajo).
Nota: En los tiempos oscuros y nebulosos, era una práctica recomendada para los programadores de C, generar código C a partir de sus diseños de intarfaz de Glade. Glade version 2 proporciona este servicio mediante el boton Construir en la barra de herramientas. Sin embargo deberías ignorar esta opción ya que sólo se aplica al lenguaje C. De hecho la recomendación actual -incluyendo a los programadores de C- es cargar el interfaz gráfico en tiempo de ejecución, lo que resulta mucho más mantenible y flexible.
Sin escribir una sola línea de código hemos creado una estructura completa de Interfaz con el usuario. Ahora hace falta un poco de código para que nuestra aplicación se ejecute.
En primer lugar, algo de administración. Importar los módulos Gtk2Hs necesarios
en las líneas 3 y 4, inicializar los gráficos en la línea 7, mostrar la ventana
en la línea 11 una vez que se han añadido todos los widgets, y llamar a la
función gráfica principal al final. Esta es la plantilla básica para todos los
módulos de usuario que usen Gtk2Hs
Para utilizar tus ficheros .glade
debes añadir algo como lo que aparece en la
línea 8. Si se encuentra el fichero especificado, tienes un modo de acceder a todos los widgets desde el programa.
1 module Main where 2 3 import Graphics.UI.Gtk 4 import Graphics.UI.Gtk.Glade 5 6 main = do 7 initGUI 8 Just xml <- xmlNew "hellogtk2hs.glade" 9 window <- xmlGetWidget xml castToWindow "window1" 10 onDestroy window mainQuit 11 widgetShowAll window 12 mainGUI
Listado de código A
La línea 9 muestra como conseguir el acceso a un widget específico usando la
función general xmlGetWidget
. El primer argumento fija al tipo de
fuente de información, el segundo indica el tipo de widget y el tercero es el
nombre del widget específico que queremos manipular (su atributo id
)
tal y como se ha especificado en el XML. Usaremos esta función continuamente.
Finalmente, la línea 10 contiene la acción que debe realizarse cuando el usuario cierra
la ventana principal.
Si tienes instalado el compilador de Haskell de Glasgow (ghc-Glasgow Haskell Compiler)
puedes usar su versión interactiva, ghci
para probar rápidamente qué tenemos
hasta el momento con nuestra función main
. (Si no te funciona el intérprete
prueba con el compilador ya que hay alguna incompatibilidad de funciones)
Todo esto es divertido y bueno, y bonito, pero nuestra aplicación es todavía palabrería ya que todavía no hace nada, así que empecemos a codificar! </p>
Ya que esto no es más que un tutorial introductorio, no vamos a hacer nada demasiado especial. Lo que queremos que ocurra es que el usuario escriba su nombre en la entrada de texto y después -cuando pulse Aplicar- cambiar el texto de la etiqueta para que lo salude con un mensaje en el que escriba, Hola seguido por el nombre que haya introducido. Además el botón Cerrar, debe cerrar la aplicación.
La idea es que cuando le sucede a un widget algo que nos interese (por ejemplo que se pulse un botón), se emite una señal, y el programador codifica lo que se debe ejecutar como respuesta a ese hecho. Por ejemplo:
onClicked button $ do ...
(Recuerda que el operador $
es el operador de aplicación de funciones
asociativas por la derecha y sólo se usa aquí para no tener que colocar todo el bloque
do
entre paréntesis.)
Empecemos creando dos manejadores de señal, uno para cada botón. Primero el botón
Close que es el más sencillo de implementar. Añadimos un poco de código trivial,
únicamente para ver nuestro evento en acción. La función putStrLn
escribe en
la salida estándar, así que vamos a usarla para saber que el botón button2
ha sido
pulsado
Antes de mainGUI
,que siempre debe ser la última instrucción, y widgetShowAll window
,
añade las dos líneas siguientes:
closeButton <- xmlGetWidget xml castToButton "button2" onClicked closeButton $ do putStrLn "Close Button Clicked"
Como puedes ver, estás usando la función xmlGetWidget
de nuevo, pero con un tipo
diferente de widget ahora. Para conseguir que el botón Cerrar funcione como su nombre indica
deberías usar la función mainQuit
en vez de putStrLn
.
Si haces esto en ghci
verás que pulsando el botón volverá a ghci
,
pero dejará la ventana y sus descendientes en la pantalla. Cuando intentes cerrar la ventana,
probablemente recibirás un mensaje del sistema operativo indicando que la aplicación no
responde o algo similar. Así que lo que necesitas es:
onClicked closeButton $ do widgetDestroy window
Esto ya si funciona, y gracias a la línea 10 en el Listado de Código A de arriba, el programa saldrá limpiamente. Y tendrás un botón Cerrar completamente funcional! </p>
Recapitulemos y recordemos lo que queremos que haga el programa cuando pulsemos el botón Aplicar. Después de que el usuario escriba su nombre en el campo de texto, queremos que en la etiqueta de arriba cambie el mensaje y ahora ponga "Hola usuario", donde usuario representa el texto que el usuario introdujo. Así este proceso precisa de dos acciones: recuperar información de un widget y establecer una propiedad de un widget..
Las funciones específicas de los widgets están bien documentadas. Incluso hay un buscador de la API. Entre otras cosas, podemos encontrar las funciones específicas para nuestras necesidades inmediatas: etiquetas (labels) y campos de texto (text entry fields).
Lo primero que necesitamos es un modo de obtener el texto introducido por el usuario. Esto
lo podemos hacer con la función get
y el atributo entryText
.
Después necesitamos una manera de establecer el texto en nuestra etiqueta. Esto se hace
con la función set
y el atributo labelText
. Y, por supuesto necesitamos
acceder a los nuevos widgets que queremos usar.Las líneas 14-16 en Listado de código B no te
sorprenderán, y la funcionalidad de las líneas 17-19 tampoco es ingeniería aeroespacial!
1 module Main where 2 3 import Graphics.UI.Gtk 4 import Graphics.UI.Gtk.Glade 5 6 main = do 7 initGUI 8 Just xml <- xmlNew "hellogtk2hs.glade" 9 window <- xmlGetWidget xml castToWindow "window1" 10 onDestroy window mainQuit 11 closeButton <- xmlGetWidget xml castToButton "button2" 12 onClicked closeButton $ do 13 widgetDestroy window 14 label <- xmlGetWidget xml castToLabel "label1" 15 entry <- xmlGetWidget xml castToEntry "entry1" 16 applyButton <- xmlGetWidget xml castToButton "button1" 17 onClicked applyButton $ do 18 name <- get entry entryText 19 set label [ labelText := "Hello " ++ name ] 20 widgetShowAll window 21 mainGUI
Listado de código B
Hecho! Guarda el programa como holagtk2hs.hs
en el mismo directorio
que nuestro fichero Glade XML, compilalo usando ghc
, y ejecuta el nuevo
binario:
$ ghc --make HelloGtk2Hs.hs -o hellogtk2hs $ ./hellogtk2hs
Escribe tu nombre en el campo de entrada de texto y pulsa Aplicar. Hola Usuario! no muy espectacular pero...
Busca en la documentación de la API de Gtk2Hs y localiza la función del evento que se genera cuando el usuario pulsa la tecla Enter y úsalo para implementar al misma funcionalidad que proporciona el botón aplicar
Ejecuta uno de los programas con ghci
, usando el comando main
, y cierra la
ventana, pero sin salir del módulo. Ahora abre el proyecto en Glade. Cambia el nombre
de la ventana y pulsa Guardar para que se actualice el fichero .glade
.
Ahora ejecuta ./holagtk2hs
de nuevo (o main
en ghci
) y
comprueba que el nombre ha cambiado Experimenta para encontrar otros cambios que puedas hacer en el GUI
manteniendo el mismo código Haskell.
Para Gtk2Hs mira Una Introducción a Gtk2Hs, Una librería gráfica de Haskell por Kenneth Hoste.(en inglés)
El documento GNOME Human Interface Guidelines (HIG) (Guía para desarrollar el interfaz con GNOME) contiene consejos detallados sobre como hacer un interfaz de usuario con buen aspecto y que encaje con el estilo del escritorio de GNOME. Muchos de los consejos se aplican a cualquier interfaz de usuario y no sólo al escritorio de GNOME.
La versión original C de este tutorial fue escrita por Eddy Ahmed. Fue adaptada para Haskell y Gtk2Hs por Hans van Thiel, en Octubre de 2006. El texto y las imágenes fueron actualizadas a Glade 3 por Alex Tarkovsky en Agosto de 2007.
Copyright 2002 Eddy Ahmed.
El texto y las imágenes han sido adaptadas y/o usadas con permiso del autor y propietario del copyright.