Estructura Básica
Vamos a crear un proyecto nuevo, del tipo GTKMM genérico.
Eliminando los comentarios el código resultante es:
#include <libglademm/xml.h>
#include <gtkmm.h>
#include <iostream>
#ifdef ENABLE_NLS
# include <libintl.h>
#endif
#define GLADE_FILE "basico.glade"
int main (int argc, char *argv[])
{
Gtk::Main kit(argc, argv);
Glib::RefPtr<Gnome::Glade::Xml> refXml;
try
{
refXml =
Gnome::Glade::Xml::create(GLADE_FILE);
}
catch(const
Gnome::Glade::XmlError& ex)
{
std::cerr
<< ex.what() << std::endl;
return 1;
}
Gtk::Window* main_win = 0;
refXml->get_widget("main_window", main_win);
if (main_win)
{
kit.run(*main_win);
}
return 0;
}
La
salida es una ventana cuyo título es Hello World! y poco
más. Tanto el título como las dimensiones no aparecen en
el código, ¿dónde se encuentran? en el archivo
nombre_programa.glade.
La utilización conjunta de Glade y
C++, implica que nuestro programa irá acompañado con un
archivo .glade, que es leído por el programa durante la
ejecución del mismo (tiempo de ejecución).
Si editamos el archivo nombre_programa.glade:
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkWindow" id="main_window">
<property name="visible">True</property>
<property name="title" translatable="yes">Hello World!</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="default_width">500</property>
<property name="default_height">400</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<child>
<placeholder/>
</child>
</widget>
</glade-interface>
Observamos que es un archivo
xml (un tipo de archivo de texto).
Glib::RefPtr<Gnome::Glade::Xml> refXml;Esta es la declaración de
refXml.
refXml es un puntero a un objeto
Gnome::Glade::Xml, que es una clase que permite la manipulación de los archivos
xml, que es lo que genera Glade.
Glib::RefPtr
aspira a ser una clase genérica de Glib para la
manipulación de los punteros (Glib tiene "copias" de los tipos
predefinidos gint para int,...) Según la documentación
esto es necesario para una adecuada gestión de la memoria,
¿?; la cuestión es que el uso de Gnome::Glade::Xml* no es
factible.
<Gnome::Glade::Xml> es la forma (plantillas) de utilizar el puntero básico de Glib como del tipo Gnome::Glade::Xml.
Este puntero hay que inicializarlo, como cualquier otro, cosa que realiza la instrucción :
refXml = Gnome::Glade::Xml::create(GLADE_FILE);Esta función recibe como argumento el archivo .glade de la aplicación.
try
{
refXml =
Gnome::Glade::Xml::create(GLADE_FILE);
}
catch(const
Gnome::Glade::XmlError& ex)
{
std::cerr
<< ex.what() << std::endl;
return 1;
}Esta
operación de inicialización puede fracasar, es decir, que
no se pueda crear el objeto. Por eso, la inicialización
está inmersa en una estructura
try ..
catch.
Si el código de try fracasa, se ejecuta el código de
catch, que básicamente informa del error y sale del programa
indicando la existencia del mismo.
Gtk::Window* main_win = 0;
refXml->get_widget("main_window", main_win);refXml es un puntero, por lo que para acceder a sus funciones miembro, debemos usar el operador [
->] . La función
get_widget
recibe dos argumentos, el primero es el nombre del widget en el archivo
glade y el segundo es el puntero del widget. Esta función crea
un nuevo widget, tomando los datos del archivo glade, y asigna la
dirección de éste a la variable puntero.
Observa que
main_win es un puntero a un Gtk::Window y no un Gtk::Window, el cual es
declarado e inicializado a 0 (no apunta a nada) en la primera
instrucción.
if (main_win)
{
kit.run(*main_win);
}A
la hora de lanzar o ejecutar el proceso, primero se comprueba que la
operación ha sido válida. Si main_win es un puntero a
Gtk::Window, *main_win es el objeto Gtk::Window.
¿quizás te preguntes las diferencias entre if y try?
Cuando verificamos con un if ( xxxx ), donde xxxx es un puntero al que
hemos asignado una parte de la memoria dinámica, esta
operación solo comprueba si el puntero era NULL,
operación fallida, o no lo era (asignación
correcta). Pero carecemos de las razones por las que se ha producido el
error, lo cual en programas extensos puede ser desalentador.
Con try...catch, la clase exception, podemos generar excepciones
y gestionarlas, informando de ellas. La clase exception, de la cual
heredará Gnome::Glade::XmlError, tiene una
función virtual what() que devuelve una cadena de texto
(para informar del tipo de error).
El programa intenta ejecutar el contenido de try, el método
Gnome::Glade::Xml::create(), si hubiera algún problema
éste lanzará la excepción
correspondiente la excepción se gestiona en catch, que no hace sino
imprimir la cadena del error correspondiente y salir del programa de
forma errónea (return 1;).