Usar widgets derivados

Puede usar Glade para distribuir sus propios widgets personalizados derivados de las clases de widgets de gtkmm. Esto mantiene su código organizado y encapsulado. Por supuesto, no verá la apariencia exacta ni las propiedades de su widget derivado en Glade, pero puede especificar su ubicación, widgets hijos y las propiedades de su clase base de gtkmm.

Use Gtk::Builder::get_widget_derived() like so:

DerivedDialog* pDialog = nullptr;
builder->get_widget_derived("DialogBasic", pDialog);

Su clase derivada debe tener un constructor que tome un puntero al tipo C subyacente, y a la instancia Gtk::Builder. Todas las clases relevantes de gtkmm crean alias de sus tipos C subyacentes como BaseObjectType (Gtk::Dialog define un alias de BaseObjectType como GtkDialog, por ejemplo).

You must call the base class's constructor in the initialization list, providing the C pointer. For instance,

DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
: Gtk::Dialog(cobject)
{
}

You could then encapsulate the manipulation of the child widgets in the constructor of the derived class, maybe using get_widget() or get_widget_derived() again. For instance,

DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
: Gtk::Dialog(cobject),
  m_builder(builder),
  m_pButton(nullptr)
{
  //Get the Glade-instantiated Button, and connect a signal handler:
  m_builder->get_widget("quit_button", m_pButton);
  if(m_pButton)
  {
    m_pButton->signal_clicked().connect( sigc::mem_fun(*this, &DerivedDialog::on_button_quit) );
  }
}

Starting with gtkmm 3.19.7, it's possible to pass additional arguments from get_widget_derived() to the constructor of the derived widget. For instance, this call to get_widget_derived()

DerivedDialog* pDialog = nullptr;
builder->get_widget_derived("DialogBasic", pDialog, true);
can invoke this constructor
DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder, bool warning)
: Gtk::Dialog(cobject),
  m_builder(builder),
  m_pButton(nullptr)
{
  // ....
}

26.3.1. Ejemplo

Este ejemplo mustra cómo cargar un archivo Glade en tiempo de ejecución y acceder a los widgets mediante una clase derivada.

Source Code

File: deriveddialog.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLE_DERIVED_DIALOG_H
#define GTKMM_EXAMPLE_DERIVED_DIALOG_H

#include <gtkmm.h>

class DerivedDialog : public Gtk::Dialog
{
public:
  DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade);
  DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade,
    bool is_glad);
  virtual ~DerivedDialog();

protected:
  //Signal handlers:
  void on_button_quit();

  Glib::RefPtr<Gtk::Builder> m_refGlade;
  Gtk::Button* m_pButton;
};

#endif //GTKMM_EXAMPLE_DERIVED_WINDOW_H

File: main.cc (For use with gtkmm 3, not gtkmm 2)

#include "deriveddialog.h"
#include <iostream>
#include <cstring>

int main (int argc, char **argv)
{
  bool show_icon = false;
  bool is_glad = true;
  int argc1 = argc;
  if (argc > 1)
  {
    if (std::strcmp(argv[1], "--glad") == 0)
    {
      show_icon = true;
      is_glad = true;
      argc1 = 1; // Don't give the command line arguments to Gtk::Application.
    }
    else if (std::strcmp(argv[1], "--sad") == 0)
    {
      show_icon = true;
      is_glad = false;
      argc1 = 1; // Don't give the command line arguments to Gtk::Application.
    }
  }

  auto app = Gtk::Application::create(argc1, argv, "org.gtkmm.example");

  //Load the Glade file and instantiate its widgets:
  auto refBuilder = Gtk::Builder::create();
  try
  {
    refBuilder->add_from_file("derived.glade");
  }
  catch(const Glib::FileError& ex)
  {
    std::cerr << "FileError: " << ex.what() << std::endl;
    return 1;
  }
  catch(const Glib::MarkupError& ex)
  {
    std::cerr << "MarkupError: " << ex.what() << std::endl;
    return 1;
  }
  catch(const Gtk::BuilderError& ex)
  {
    std::cerr << "BuilderError: " << ex.what() << std::endl;
    return 1;
  }

  //Get the GtkBuilder-instantiated dialog:
  DerivedDialog* pDialog = nullptr;
  if (show_icon)
    // This call to get_widget_derived() requires gtkmm 3.19.7 or higher.
    refBuilder->get_widget_derived("DialogDerived", pDialog, is_glad);
  else
    refBuilder->get_widget_derived("DialogDerived", pDialog);
  if(pDialog)
  {
    //Start:
    app->run(*pDialog);
  }

  delete pDialog;

  return 0;
}

File: deriveddialog.cc (For use with gtkmm 3, not gtkmm 2)

#include "deriveddialog.h"

DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade)
: Gtk::Dialog(cobject),
  m_refGlade(refGlade),
  m_pButton(nullptr)
{
  //Get the Glade-instantiated Button, and connect a signal handler:
  m_refGlade->get_widget("quit_button", m_pButton);
  if(m_pButton)
  {
    m_pButton->signal_clicked().connect( sigc::mem_fun(*this, &DerivedDialog::on_button_quit) ); 
  }
}

// The first two parameters are mandatory in a constructor that will be called
// from Gtk::Builder::get_widget_derived().
// Additional parameters, if any, correspond to additional arguments in the call
// to Gtk::Builder::get_widget_derived().
DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade,
  bool is_glad)
: DerivedDialog(cobject, refGlade) // Delegate to the other constructor
{
  // Show an icon.
  auto pImage = Gtk::manage(new Gtk::Image());
  pImage->set_from_icon_name(is_glad ? "face-smile" : "face-sad", Gtk::ICON_SIZE_DIALOG);
  pImage->show_all();
  get_content_area()->pack_start(*pImage);
}

DerivedDialog::~DerivedDialog()
{
}

void DerivedDialog::on_button_quit()
{
  hide(); //hide() will cause Gtk::Application::run() to end.
}