Glade con Clases
En C++, lo suyo es programar con clases. A mi parecer, libglademm no
está muy bien desarrollado para trabajar con clases. He
buscado ejemplos de implementaciones de C++ con Glade, y no he
encontrado nada más que un simple ejemplo, a partir del cual
desarrollo el apartado posterior.
Tal y como hicimos con Gtk(con clases), uno tiene
la
tentación de simplificar al máximo la
función
main(), introduciendo casi todas las operaciones en el constructor de
la clase, quedando así:
// main.cc
#include <gtkmm.h>
#include <libglademm/xml.h>
#include "miventanica.h"
int main(int argc, char *argv[])
{
Gtk::Main programa(argc, argv);
miventanica ventana;
Gtk::Main::run(*ventana.yo);
return 0;
}
//
miventanica.h
#include <gtkmm.h>
#include <libglademm/xml.h>
// DECLARACIÓN DE LA CLASE
class miventanica
{
public:
miventanica();
virtual ~miventanica();
Gtk::Window * yo;
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"
// DEFINICIÓN DE LOS MÉTODOS DE LA CLASE
miventanica::miventanica()
{
veces=0;
refXml = Gnome::Glade::Xml::create("basico.glade");
refXml->get_widget("miventanica", yo);
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(){
char h[30];
sprintf (h, "has pulsado %i veces el
botón", ++veces);
etiqueta->set_text(h);
}
Básicamente, hemos escondido el
código anterior en una clase.
La
única modificación importante es que la clase miventanica
no es una Gtk::Window, sino que contiene una (*yo). Lo he hecho
así porque ninguna de
las
instrucciones siguientes eran reconocidas:
refXml->get_widget
("miventanica", this);
refXml->get_widget
("miventanica", (Gtk::Window* )this);La
función run de Gtk::Main requiere una Gtk::Window, miventanica
no lo es, por tanto precisamos que *yo sea público, accesible.
Así,
funciona... Sin embargo, no es muy buena opción, ¿?
En nuestro ejemplo, existe solo una ventana, ¿pero
qué ocurre con proyectos que utilizan muchas ventanas
(fuentes,
colores, grabar archivos, configuración,
impresión,...)?
Si cada ventana tiene su clase (como es normal) y cada ventana "carga"
el documento .glade, tendremos nuestra RAM almacenando innecesariamente
el mismo documento varias veces.
La solución pasa por declarar en inicializar en main a refXml
y que las clases
tengan una referencia al mismo:
Para ello, debemos pasar la dirección de memoria del documento
a la clase...
Modifiquemos
nuestro archivo glade para que incluya una segunda ventana: un cuadro
de diálogo, con un botón [aceptar]. Tal que
así:
Editemos el nombre de la
ventana y del botón:
ventana: Nombre->
dialogo
botón: Nombre->
botonAceptar
y SOBRETODO
no se nos olvide poner dialogo como
NO visible (en Propiedades-
Comunes-Visible), porque de lo
contrario no aparecerá cuando nosotros queramos, sino al
principio.
//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);
Gtk::Main::run(*ventana.yo);
return 0;
}
//miventanica.h
#include <gtkmm.h>
#include <libglademm/xml.h>
// DECLARACIÓN DE LA CLASE
class miventanica
{
public:
miventanica(Glib::RefPtr<Gnome::Glade::Xml>);
virtual ~miventanica();
Gtk::Window * yo;
protected:
int veces;
Glib::RefPtr<Gnome::Glade::Xml> refXml;
Gtk::Button* boton;
Gtk::Label* etiqueta;
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
miventanica::miventanica(Glib::RefPtr<Gnome::Glade::Xml>
xxx)
{
veces=0;
refXml = xxx;
refXml->get_widget("miventanica", yo);
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);
ventanita.yo->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:
miventanica2(Glib::RefPtr<Gnome::Glade::Xml>);
virtual ~miventanica2();
Gtk::Dialog * yo;
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"
// DEFINICIÓN DE LOS MÉTODOS DE LA CLASE
//constructor
miventanica2::miventanica2(Glib::RefPtr<Gnome::Glade::Xml>
xxx)
{
refXml = xxx;
refXml->get_widget("dialogo", yo);
refXml->get_widget("botonAceptar", botonAceptar);
botonAceptar->signal_clicked().connect(sigc::mem_fun(*this,&miventanica2::pulsa_botonAceptar));
}
miventanica2::~miventanica2(){}
void miventanica2::pulsa_botonAceptar(){ yo->hide();}
Las diferencias están en la declaración de las
ventanas, que incorporan como argumento la referencia al documento xml.
El diálogo solo se abre la primera vez que se pulsa sobre el botón.