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 gives the window a title, and puts a Gtk::Stack
widget as the main content.
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. If you build with Meson,
use the compile_resources()
function in Meson's
GNOME module.
Our application now looks like this:
File: exampleapplication.h
(For use with gtkmm 4)
#include "../step1/exampleapplication.h" // Equal to the corresponding file in step1
File: exampleappwindow.h
(For use with gtkmm 4)
#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.cc
(For use with gtkmm 4)
#include "exampleapplication.h" #include "exampleappwindow.h" #include <iostream> #include <exception> ExampleApplication::ExampleApplication() : Gtk::Application("org.gtkmm.examples.application", Gio::Application::Flags::HANDLES_OPEN) { } Glib::RefPtr<ExampleApplication> ExampleApplication::create() { return Glib::make_refptr_for_instance<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); // A window can be added to an application with Gtk::Application::add_window() // or Gtk::Window::set_application(). When all added windows have been hidden // or removed, the application stops running (Gtk::Application::run() returns()), // unless Gio::Application::hold() has been called. // Delete the window when it is hidden. appwindow->signal_hide().connect([appwindow](){ delete 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; } }
File: exampleappwindow.cc
(For use with gtkmm 4)
#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"); auto window = Gtk::Builder::get_widget_derived<ExampleAppWindow>(refBuilder, "app_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: main.cc
(For use with gtkmm 4)
#include "../step1/main.cc" // Equal to the corresponding file in step1
File: exampleapp.gresource.xml
(For use with gtkmm 4)
<?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 4)
<?xml version="1.0" encoding="UTF-8"?> <interface> <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> <property name="hide-on-close">True</property> <child> <object class="GtkBox" id="content_box"> <property name="orientation">vertical</property> <child> <object class="GtkStack" id="stack"/> </child> </object> </child> </object> </interface>