Manual
logo



Programación C++ con AGU desde 0

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.