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:
- recibir un puntero básico de las classes Gtk: BaseObjectType*
- recibir una instancia de Gnome::Glade::Xml
(tal y como hicimos en el ejemplo último).
//
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:
- 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-).
- ¿ 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".