Aunque a veces, cuando nos dedicamos a programar en Linux, recurrimos a la consola (ya que muchos de nosotros tenemos siempre una abierta), a veces es interesante crear un Interfaz Gráfico de Usuario (en inglés GUI, Graphical User Interface), para ello, si no queremos complicarnos demasiado tenemos dos opciones: Gtk+ y Qt.
Bien, vamos con Gtk+, está muy extendido y escrita en C, aunque aquí hablaré de una interfaz de Gtk+ para C++ llamada gtkmm, que nos proporciona las clases necesarias para jugar con la potencia de Gtk+ de una forma un poco más amigable (ya que podemos crear un botón, una etiqueta o una ventana como objetos de C++, hará todo un poco más intuitivo).
Una primera prueba que me gusta hacer es poner todo el código junto, sin mucha organización, para crear un «hola mundo», para ver más o menos a qué nos enfrentamos y cómo, si vamos a tener que escribir mucho y esas cosas:
[ holamundo.cpp]
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 | #include <gtkmm.h> using namespace Gtk; int main(int argc, char *argv[]) { // Inicialización GTK Main entorno(argc, argv); // Declaración de objetos Window ventana; Label etiqueta; // Características de la ventana ventana.set_title("Hola Mundo!"); ventana.set_border_width(5); ventana.set_default_size(400, 200); // Etiqueta etiqueta.set_text("Hola Mundo!!"); ventana.add(etiqueta); // Mostrar todo ventana.show_all_children(); // Ejecutar GUI entorno.run(ventana); return 0; } |
Para compilar debemos hacer lo siguiente:
$ g++ -o holamundo holamundo.cpp `pkg-config –cflags gtkmm-2.4` `pkg-config –libs gtkmm-2.4`
Eso sí, debemos sustituir el 2.4 por la versión de gtkmm que tengamos instalada. Para ver cuál es, podemos hacer lo siguiente:
$ pkg-config –list-all | grep gtkmm
Bien, una vez hecho esto, vamos a intentar adquirir una metodología de programación que nos permita reaprovechar código, y tenerlo todo organizado, vamos a crear archivos .h y .cpp:
[ hworld.h ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #ifndef _HWORLD_H #define _HWORLD_H #include <gtkmm.h> using namespace Gtk; class HolaMundo : public Window { public: HolaMundo(); ~HolaMundo(); Label etiqueta; }; #endif |
[ hworld.cpp ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include "hworld.h" HolaMundo::HolaMundo() { this->set_title("Hola Mundo!"); this->set_border_width(5); this->set_default_size(400, 200); etiqueta.set_text("Hola Mundo!!"); this->add(etiqueta); this->show_all_children(); } HolaMundo::~HolaMundo() { } |
[ hellomain.cpp ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <gtkmm.h> #include "hworld.h" int main(int argc, char *argv[]) { Main entorno (argc, argv); // Creamos la ventana HolaMundo hmundo; // Ejecutamos entorno.run(hmundo); return 0; } |
Ahora compilamos con:
$ g++ -o hellom hellomain.cpp hworld.cpp `pkg-config –cflags gtkmm-2.4` `pkg-config –libs gtkmm-2.4`
Hará lo mismo, ¡vaya tontería! pero lo tendremos todo mucho más organizado, hemos introducido todo lo referente a la ventana en una misma clase.
Una pequeña nota: escribo arriba using namespace Gtk para no repetir todo el rato Gtk::[Tipo] , Gtk::[Método], ya que todo lo que estoy utilizando hasta ahora pertenece al espacio Gtk.
Ahora vamos a hacer algo más complicado, vamos a utilizar algunos elementos más y vamos a introducir algún botón, para que se desempeñe alguna acción:
[ hworld.h ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #ifndef _HWORLD_H #define _HWORLD_H #include <gtkmm.h> using namespace Gtk; class HolaMundo : public Window { public: HolaMundo(); ~HolaMundo(); void click_salir(); void click_mensaje(); VBox cajaV; HButtonBox botonera; Label etiqueta; Button *botonSalir, *botonMensaje; }; #endif |
Creamos un objeto derivado de Gtk::Window en el que incluimos los elementos que habrá en la ventana:
- VBox es una caja con divisiones horizontales, es como si cortáramos horizontalmente en trozos a lo largo de la vertical
- HButtonBox es una caja para poner botones a lo largo de la horizontal
- Button es un botón. Pondremos dos, uno para salir y otro para mostrar un mensaje emergente
- Label es nuestra etiqueta de «Hola Mundo»
Definimos dos métodos para los eventos click_salir() y click_mensaje().
Los botones los he declarado como punteros para demostrar cómo podemos trabajar con objetos de este tipo.
[ hworld.cpp ]
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include "hworld.h" #include <sstream> // Para hacer string<<int HolaMundo::HolaMundo() { // Configuro la ventana set_title("Hola Mundo!"); set_border_width(5); set_default_size(400, 200); // Configuro la etiqueta etiqueta.set_text("Hola Mundo!!"); // Configuro la botonera botonSalir=new Button(Stock::QUIT); botonMensaje=new Button("Mensaje"); botonSalir->signal_clicked().connect(sigc::mem_fun(*this, &HolaMundo::click_salir)); botonMensaje->signal_clicked().connect(sigc::mem_fun(*this, &HolaMundo::click_mensaje)); botonera.pack_start(*botonSalir, PACK_SHRINK); botonera.pack_start(*botonMensaje, PACK_SHRINK); // Configuro la división add(cajaV); cajaV.pack_start(etiqueta, PACK_EXPAND_WIDGET); // Esto ocupará el máximo tamaño cajaV.pack_start(botonera, PACK_SHRINK); show_all_children(); } HolaMundo::~HolaMundo() { delete botonSalir; delete botonMensaje; } void HolaMundo::click_mensaje() { int res; std::stringstream ss; MessageDialog dialog("Esto es un mensaje emergente"); res=dialog.run(); if (res==RESPONSE_OK) etiqueta.set_text("Has dicho OK"); else if (res==RESPONSE_DELETE_EVENT) etiqueta.set_text("Has cancelado el diálogo"); else { ss<<"Has respondido otra cosa: "<<res; etiqueta.set_text(ss.str().data()); } } void HolaMundo::click_salir() { hide(); } |
Vemos cómo en el constructor hemos configurado todos los elementos de la ventana, vemos cómo en la botonera y la cajaV, para añadir objetos se ha utilizado el método pack_start, las propiedades Gtk::PACK_SHRINK (encogerá el objeto contenedor) y Gtk::PACK_EXPAND_WIDGET (lo expanderá)
Pero la cajaV la añadiremos a la ventana con el método add.
Los botones los creamos con new (recordamos que eran punteros), tenemos muchos botones de Stock predefinidos, y podemos crear uno con esta propiedad (todos están en Gtk::Stock::XXXXX), aunque también podemos crearlos directamente con un texto.
Para conectar los eventos (de los botones por ejemplo) usamos connect(), como parámetro podemos incluir una función (con sigc::ptr_fun(&funcion)) o un método de clase (con sigc::mem_fun(*objeto, &Clase::metodo)), será la función o método que llamaremos cuando se genere el evento (en este ejemplo será el click sobre el botón).
Además, incluyo una caja de diálogo en la que luego distinguimos si se cierra por el botón aceptar (Gtk::RESPONSE_OK), o cerrando la ventana (Gtk::RESPONSE_DELETE_EVENT) modificando el texto del Label.
[ hellomain.cpp ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <gtkmm.h> #include "hworld.h" int main(int argc, char *argv[]) { Main entorno (argc, argv); // Creamos la ventana HolaMundo hmundo; // Ejecutamos entorno.run(hmundo); return 0; } |
Como vemos, el programa principal es exactamente igual que el anterior, como la compilación del proyecto:
g++ -o hellom hellomain.cpp hworld.cpp `pkg-config –cflags gtkmm-2.4` `pkg-config –libs gtkmm-2.4`
Pingback: Bitacoras.com /
Pingback: BlogESfera.com /
Hola k tal!
Podrías ayudarme con la instalación de gtkmm?
Al ejecutar en consola el comando para saber que versión tengo instalada me devuelve:
$ pkg-config –list-all | grep gtkmm
Failed to open ‘/usr/lib64/pkgconfig/cblas.pc’: No such file or directory
Failed to open ‘/usr/lib64/pkgconfig/libgcj-4.3.pc’: No such file or directory
Package dri2proto was not found in the pkg-config search path.
Perhaps you should add the directory containing `dri2proto.pc’
to the PKG_CONFIG_PATH environment variable
Package ‘dri2proto’, required by ‘gl’, not found
Estoy en Sabayon 5.3 KDE de 64bits y no se como instalar los paquetes de gtkmm 🙁
En los repositorios de Sabayon estan los siguientes paquetes y tengo los 3 instalados:
# equo search gtkmm
>> @@ Buscando…
>> @@ Paquete: app-emulation/emul-linux-x86-gtkmmlibs-20100611 rama: 5, [repo_sabayonlinux.org]
>> Disponible: versión: 20100611 ~ tag: NoTag ~ revisión: 0
>> Instalado: versión: 20100611 ~ tag: NoTag ~ revisión: 0
>> Bloque: 0
>> Página: http://dev.gentoo.org/~pacho/emul.html
>> Descripción: Provides precompiled 32bit libraries
>> Licencia: LGPL-2.1 GPL-2 LGPL-2
>> @@ Paquete: dev-cpp/gtkmm-2.2.12 rama: 5, [repo_sabayonlinux.org]
>> Disponible: versión: 2.2.12 ~ tag: NoTag ~ revisión: 2
>> Instalado: versión: 2.2.12 ~ tag: NoTag ~ revisión: 2
>> Bloque: 2
>> Página: http://gtkmm.sourceforge.net/
>> Descripción: C++ interface for GTK+2
>> Licencia: LGPL-2.1
>> @@ Paquete: dev-cpp/gtkmm-2.20.3 rama: 5, [repo_sabayonlinux.org]
>> Disponible: versión: 2.20.3 ~ tag: NoTag ~ revisión: 0
>> Instalado: versión: 2.20.3 ~ tag: NoTag ~ revisión: 0
>> Bloque: 2.4
>> Página: http://www.gtkmm.org
>> Descripción: C++ interface for GTK+2
>> Licencia: LGPL-2.1
>> Palabras clave: gtkmm
>> Encontrados: 3 entradas
Quisiera empezar a desarrollar en gtkmm ya, pero necesito instalarlo primero.
Alguna sugerencia?
@Karit
Hola Karit, yo creo que debes instalar:
@@ Paquete: dev-cpp/gtkmm-2.20.3 , el último de los que me dices, ¿ equo install ? Instala el paquete y yo creo que podrás empezar a trabajar ya, si quieres, instala glade-3, estoy preparando un post para utilizar glade y gtkbuilder, nos ayudará a crear GUIs de forma más fácil.
De todas formas, parece que tienes problemas con cblas, libgjc y dri2proto y por eso pkg-config se queja, pero no es demasiado problema.
Ya me dices si hay suerte.
MMM no se dejó… =(
Tuve que instalar gtkmm desde el código fuente y ahora solo puedo compilar como usuario root.
Jeje creo que algo hize mal en mi compilación…
sin embargo no todo es tan feo, ya pude crear mi primera ventanita con gtkmm.
Espero aprender más acerca de su uso ya que hasta el momento me gusta mas QT..
THANKS!
@Karit
Ánimo !! Ya nos contarás.