Manual
logo



Programación C++ con AGU desde 0

Glade con Clases

La opción de GTK

Gtk tiene implementado un método en Gnome::Glade::Xml que nos va a permitir heredar directamente de Gtk::Window:
get_widget_derived("nombre_glade_widget", puntero_clase_derivada);
El cual impone dos obligaciones al constructor:
// main.cc

#include <gtkmm.h>
#include <libglademm/xml.h>
#include <iostream>
#include "miventanica.h"


int main(int argc, char *argv[])
{
      
    Gtk::Main programa(argc, argv);
    Glib::RefPtr<Gnome::Glade::Xml> refXml;
  try
  {
    refXml = Gnome::Glade::Xml::create("basico.glade");
  }
  catch(const Gnome::Glade::XmlError& ex)
  {
    std::cerr << ex.what() << std::endl;
    return 1;
  }
 
   miventanica* ventana;
 
   refXml->get_widget_derived("miventanica", ventana); 
   if(ventana){
    Gtk::Main::run(*ventana);
   }
    return 0;
}
Este main es muy parecido a la estructura básica que crea Anjuta. Simplemente debemos añadir el archivo de nuestra clase (#include "miventanica.h"), declarar un puntero a nuestra clase, en vez de a Gtk::Window (miventanica* ventana;), y finalmente sustituir get_widget por get_widget_derived.
//miventanica.h

#include <gtkmm.h>
#include <libglademm/xml.h>

class miventanica:public Gtk::Window
{
     public:
         miventanica(BaseObjectType* www, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade);

        virtual ~miventanica();
      
    protected:
        int veces;
      
         Glib::RefPtr<Gnome::Glade::Xml> refXml;
       
         Gtk::Button* boton;
         Gtk::Label* etiqueta;

        // señales
        virtual void pulsa_contador();
 
};


//miventanica.cc

#include <gtkmm.h>
#include <iostream>
#include <stdlib.h>
#include <libglademm/xml.h>
#include "miventanica.h"
#include "miventanica2.h"
// DEFINICIÓN DE LOS MÉTODOS DE LA CLASE
// constructor de la primera clase
miventanica::miventanica(BaseObjectType* www, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade):Gtk::Window(www),refXml(refGlade)
{
        veces=0;
        refXml->get_widget("boton", boton);
      
        boton->signal_clicked().connect(sigc::mem_fun(*this,&miventanica::pulsa_contador));
     
        refXml->get_widget("etiqueta", etiqueta);

}

// destructor
miventanica::~miventanica(){std::cout<<"Eso es todo amigo"<<std::endl;}
 
// función para manipular la señal
void miventanica::pulsa_contador(){
    if (veces==0){
        miventanica2* ventanita;
        refXml->get_widget_derived("dialogo", ventanita);
        ventanita->run();
    }
    char h[30];
    sprintf (h, "has pulsado %i veces el botón", ++veces);

    etiqueta->set_text(h);
}


//miventanica2.h

#include <gtkmm.h>
#include <libglademm/xml.h>



class miventanica2:public Gtk::Dialog
{
     public:
         miventanica2(BaseObjectType* www, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade);
        virtual ~miventanica2();
      
    protected:
           
         Glib::RefPtr<Gnome::Glade::Xml> refXml;
         Gtk::Button* botonAceptar;
         virtual void pulsa_botonAceptar();
};    




// miventanica2.cc

#include <gtkmm.h>
#include <libglademm/xml.h>
#include "miventanica2.h"
miventanica2::miventanica2(BaseObjectType* www, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade):Gtk::Dialog(www),refXml(refGlade)
{
          
        refXml->get_widget("botonAceptar", botonAceptar);
        botonAceptar->signal_clicked().connect(sigc::mem_fun(*this,&miventanica2::pulsa_botonAceptar));
}

miventanica2::~miventanica2(){}

void miventanica2::pulsa_botonAceptar(){ hide();}


Personalmente, veo dos problemillas:
  1. El constructor de la clase resulta algo engorroso (entre otras cosas porque la creación del objeto se produce dentro de get_widget_derived, y no alcanzo a saber a ciencia cierta la forma en que se realiza -limitaciones que tiene uno-). 
  2. ¿ y el "Eso es todo, amigo" ?. No se ha ejecutado el destructor, esto implica que la memoria ocupada no ha sido liberada. Podemos comprobarlo: abre un terminal y ejecuta  cat /proc/meminfo , observa el valor de MemFree; luego ejecuta nuestro programa y ciérralo, vuelve a comprobar la memoria (es menor), afortunadamente nuestro programa es pequeño.
Para mí, es un error, pues como muchas cosas en la vida (el que la hace, la paga; el que la tira va por ella,...), el encargado de reservar la memoria, debe ser el que la libere. Sin embargo, está formula no lo hace. Debemos liberarla nosotros. ... Lo cual es muy sencillo, simplemente añadir dos delete:

// main.cc

#include <gtkmm.h>
#include <libglademm/xml.h>
#include <iostream>
#include "miventanica.h"


int main(int argc, char *argv[])
{
      
    Gtk::Main programa(argc, argv);
    Glib::RefPtr<Gnome::Glade::Xml> refXml;
  try
  {
    refXml = Gnome::Glade::Xml::create("basico.glade");
  }
  catch(const Gnome::Glade::XmlError& ex)
  {
    std::cerr << ex.what() << std::endl;
    return 1;
  }
 
   miventanica* ventana;
 
   refXml->get_widget_derived("miventanica", ventana); 
   if(ventana){
    Gtk::Main::run(*ventana);
   }
   delete ventana;
    return 0;
}

//miventanica.cc

#include <gtkmm.h>
#include <iostream>
#include <stdlib.h>
#include <libglademm/xml.h>
#include "miventanica.h"
#include "miventanica2.h"
// DEFINICIÓN DE LOS MÉTODOS DE LA CLASE
// constructor de la primera clase
miventanica::miventanica(BaseObjectType* www, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade):Gtk::Window(www),refXml(refGlade)
{
        veces=0;
        refXml->get_widget("boton", boton);
      
        boton->signal_clicked().connect(sigc::mem_fun(*this,&miventanica::pulsa_contador));
     
        refXml->get_widget("etiqueta", etiqueta);

}

// destructor
miventanica::~miventanica(){std::cout<<"Eso es todo amigo"<<std::endl;}
 
// función para manipular la señal
void miventanica::pulsa_contador(){
    if (veces==0){
        miventanica2* ventanita;
        refXml->get_widget_derived("dialogo", ventanita);
        ventanita->run();
        delete ventanita;
    }
    char h[30];
    sprintf (h, "has pulsado %i veces el botón", ++veces);

    etiqueta->set_text(h);
}
Observa como ahora si aparece "Eso es todo amigo".