In this step, we use a Gtk::Builder
instance to associate a
Gtk::Builder
ui file with our application window class.
Our simple ui file puts a Gtk::HeaderBar
on top of a
Gtk::Stack
widget. The header bar contains a
Gtk::StackSwitcher
, which is a standalone widget to show a row
of 'tabs' for the pages of a Gtk::Stack
.
To make use of this file in our application, we revisit our
Gtk::ApplicationWindow
subclass, and call
Gtk::Builder::create_from_resource()
and
Gtk::Builder::get_widget_derived()
from the
ExampleAppWindow::create()
method to get an instance of
our subclassed Gtk::ApplicationWindow
. See the
Using derived widgets section
for more information about get_widget_derived()
.
You may have noticed that we use the _from_resource()
variant
of the method that reads the ui file. Now we need to use GLib's
resource functionality to include the ui file in the binary. This is commonly done by
listing all resources in a .gresource.xml file.
This file has to be converted into a C source file that will be compiled and linked
into the application together with the other source files. To do so, we use the
glib-compile-resources utility:
$ glib-compile-resources --target=resources.c --generate-source exampleapp.gresource.xml
The Gio::Resource and glib-compile-resources section contains more information about resource files.
Our application now looks like this:
File: exampleappwindow.h
(For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEAPPWINDOW_H_ #define GTKMM_EXAMPLEAPPWINDOW_H_ #include <gtkmm.h> class ExampleAppWindow : public Gtk::ApplicationWindow { public: ExampleAppWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder); static ExampleAppWindow* create(); void open_file_view(const Glib::RefPtr<Gio::File>& file); protected: Glib::RefPtr<Gtk::Builder> m_refBuilder; }; #endif /* GTKMM_EXAMPLEAPPWINDOW_H */
File: exampleapplication.h
(For use with gtkmm 3, not gtkmm 2)
#include "../step1/exampleapplication.h" // Equal to the corresponding file in step1
File: exampleapplication.cc
(For use with gtkmm 3, not gtkmm 2)
#include "exampleapplication.h" #include "exampleappwindow.h" #include <iostream> #include <exception> ExampleApplication::ExampleApplication() : Gtk::Application("org.gtkmm.examples.application", Gio::APPLICATION_HANDLES_OPEN) { } Glib::RefPtr<ExampleApplication> ExampleApplication::create() { return Glib::RefPtr<ExampleApplication>(new ExampleApplication()); } ExampleAppWindow* ExampleApplication::create_appwindow() { auto appwindow = ExampleAppWindow::create(); // Make sure that the application runs for as long this window is still open. add_window(*appwindow); // Gtk::Application::add_window() connects a signal handler to the window's // signal_hide(). That handler removes the window from the application. // If it's the last window to be removed, the application stops running. // Gtk::Window::set_application() does not connect a signal handler, but is // otherwise equivalent to Gtk::Application::add_window(). // Delete the window when it is hidden. appwindow->signal_hide().connect(sigc::bind<Gtk::Window*>(sigc::mem_fun(*this, &ExampleApplication::on_hide_window), appwindow)); return appwindow; } void ExampleApplication::on_activate() { try { // The application has been started, so let's show a window. auto appwindow = create_appwindow(); appwindow->present(); } // If create_appwindow() throws an exception (perhaps from Gtk::Builder), // no window has been created, no window has been added to the application, // and therefore the application will stop running. catch (const Glib::Error& ex) { std::cerr << "ExampleApplication::on_activate(): " << ex.what() << std::endl; } catch (const std::exception& ex) { std::cerr << "ExampleApplication::on_activate(): " << ex.what() << std::endl; } } void ExampleApplication::on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& /* hint */) { // The application has been asked to open some files, // so let's open a new view for each one. ExampleAppWindow* appwindow = nullptr; auto windows = get_windows(); if (windows.size() > 0) appwindow = dynamic_cast<ExampleAppWindow*>(windows[0]); try { if (!appwindow) appwindow = create_appwindow(); for (const auto& file : files) appwindow->open_file_view(file); appwindow->present(); } catch (const Glib::Error& ex) { std::cerr << "ExampleApplication::on_open(): " << ex.what() << std::endl; } catch (const std::exception& ex) { std::cerr << "ExampleApplication::on_open(): " << ex.what() << std::endl; } } void ExampleApplication::on_hide_window(Gtk::Window* window) { delete window; }
File: main.cc
(For use with gtkmm 3, not gtkmm 2)
#include "../step1/main.cc" // Equal to the corresponding file in step1
File: exampleappwindow.cc
(For use with gtkmm 3, not gtkmm 2)
#include "exampleappwindow.h" #include <stdexcept> ExampleAppWindow::ExampleAppWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder) : Gtk::ApplicationWindow(cobject), m_refBuilder(refBuilder) { } //static ExampleAppWindow* ExampleAppWindow::create() { // Load the Builder file and instantiate its widgets. auto refBuilder = Gtk::Builder::create_from_resource("/org/gtkmm/exampleapp/window.ui"); ExampleAppWindow* window = nullptr; refBuilder->get_widget_derived("app_window", window); if (!window) throw std::runtime_error("No \"app_window\" object in window.ui"); return window; } void ExampleAppWindow::open_file_view(const Glib::RefPtr<Gio::File>& /* file */) { }
File: exampleapp.gresource.xml
(For use with gtkmm 3, not gtkmm 2)
<?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/org/gtkmm/exampleapp"> <file preprocess="xml-stripblanks">window.ui</file> </gresource> </gresources>
File: window.ui
(For use with gtkmm 3, not gtkmm 2)
<?xml version="1.0" encoding="UTF-8"?> <interface> <!-- interface-requires gtk+ 3.8 --> <object class="GtkApplicationWindow" id="app_window"> <property name="title" translatable="yes">Example Application</property> <property name="default-width">600</property> <property name="default-height">400</property> <child> <object class="GtkBox" id="content_box"> <property name="visible">True</property> <property name="orientation">vertical</property> <child> <object class="GtkHeaderBar" id="header"> <property name="visible">True</property> <child type="title"> <object class="GtkStackSwitcher" id="tabs"> <property name="visible">True</property> <property name="stack">stack</property> </object> </child> </object> </child> <child> <object class="GtkStack" id="stack"> <property name="visible">True</property> </object> </child> </object> </child> </object> </interface>