Manual
logo



Programación C++ con AGU desde 0

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;).