You can use Glade to layout your own custom widgets derived from gtkmm widget classes. This keeps your code organized and encapsulated. Of course you won't see the exact appearance and properties of your derived widget in Glade, but you can specify its location and child widgets and the properties of its gtkmm base class.
Use Gtk::Builder::get_widget_derived()
like so:
DerivedDialog* pDialog = nullptr; builder->get_widget_derived("DialogBasic", pDialog);
Your derived class must have a constructor that takes a pointer to the
underlying C type, and the Gtk::Builder
instance.
All relevant classes of gtkmm typedef their underlying C type as
BaseObjectType
(Gtk::Dialog
typedefs BaseObjectType
as GtkDialog, for instance).
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) { // .... }
This example shows how to load a Glade file at runtime and access the widgets via a derived class.
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::make_managed<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. }