This program contains an application menu, a menubar and a toolbar.
Classes are derived from Gtk::Application
and
Gtk::ApplicationWindow
.
File: exampleapplication.h
(For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEAPPLICATION_H
#define GTKMM_EXAMPLEAPPLICATION_H
#include <gtkmm.h>
class ExampleApplication : public Gtk::Application
{
protected:
ExampleApplication();
public:
static Glib::RefPtr<ExampleApplication> create();
protected:
//Overrides of default signal handlers:
void on_startup() override;
void on_activate() override;
private:
void create_window();
void on_menu_file_new_generic();
void on_menu_file_quit();
void on_menu_help_about();
Glib::RefPtr<Gtk::Builder> m_refBuilder;
};
#endif /* GTKMM_EXAMPLEAPPLICATION_H */
File: examplewindow.h
(For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::ApplicationWindow
{
public:
ExampleWindow();
virtual ~ExampleWindow();
protected:
//Signal handlers:
void on_menu_others();
void on_menu_choices(const Glib::ustring& parameter);
void on_menu_choices_other(int parameter);
void on_menu_toggle();
//Child widgets:
Gtk::Box m_Box;
Glib::RefPtr<Gtk::Builder> m_refBuilder;
//Two sets of choices:
Glib::RefPtr<Gio::SimpleAction> m_refChoice;
Glib::RefPtr<Gio::SimpleAction> m_refChoiceOther;
Glib::RefPtr<Gio::SimpleAction> m_refToggle;
};
#endif //GTKMM_EXAMPLEWINDOW_H
File: exampleapplication.cc
(For use with gtkmm 4)
#include "exampleapplication.h"
#include "examplewindow.h"
#include <iostream>
ExampleApplication::ExampleApplication()
: Gtk::Application("org.gtkmm.example.main_menu")
{
Glib::set_application_name("Main Menu Example");
}
Glib::RefPtr<ExampleApplication> ExampleApplication::create()
{
return Glib::make_refptr_for_instance<ExampleApplication>(new ExampleApplication());
}
void ExampleApplication::on_startup()
{
//Call the base class's implementation:
Gtk::Application::on_startup();
//Create actions for menus and toolbars.
//We can use add_action() because Gtk::Application derives from Gio::ActionMap.
//File|New sub menu:
add_action("newstandard",
sigc::mem_fun(*this, &ExampleApplication::on_menu_file_new_generic));
add_action("newfoo",
sigc::mem_fun(*this, &ExampleApplication::on_menu_file_new_generic));
add_action("newgoo",
sigc::mem_fun(*this, &ExampleApplication::on_menu_file_new_generic));
//File menu:
add_action("quit", sigc::mem_fun(*this, &ExampleApplication::on_menu_file_quit));
//Help menu:
add_action("about", sigc::mem_fun(*this, &ExampleApplication::on_menu_help_about));
// Set accelerator keys:
set_accel_for_action("app.newstandard", "<Primary>n");
set_accel_for_action("app.quit", "<Primary>q");
set_accel_for_action("win.copy", "<Primary>c");
set_accel_for_action("win.paste", "<Primary>v");
m_refBuilder = Gtk::Builder::create();
//Layout the actions in a menubar and a menu:
Glib::ustring ui_info =
"<interface>"
" <!-- menubar -->"
" <menu id='menu-example'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_File</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>New _Standard</attribute>"
" <attribute name='action'>app.newstandard</attribute>"
" <attribute name='accel'><Primary>n</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>New _Foo</attribute>"
" <attribute name='action'>app.newfoo</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>New _Goo</attribute>"
" <attribute name='action'>app.newgoo</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Quit</attribute>"
" <attribute name='action'>app.quit</attribute>"
" <attribute name='accel'><Primary>q</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Edit</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Copy</attribute>"
" <attribute name='action'>win.copy</attribute>"
" <attribute name='accel'><Primary>c</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Paste</attribute>"
" <attribute name='action'>win.paste</attribute>"
" <attribute name='accel'><Primary>v</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Something</attribute>"
" <attribute name='action'>win.something</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Choices</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>Choice _A</attribute>"
" <attribute name='action'>win.choice</attribute>"
" <attribute name='target'>a</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>Choice _B</attribute>"
" <attribute name='action'>win.choice</attribute>"
" <attribute name='target'>b</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Other Choices</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>Choice 1</attribute>"
" <attribute name='action'>win.choiceother</attribute>"
" <attribute name='target' type='i'>1</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>Choice 2</attribute>"
" <attribute name='action'>win.choiceother</attribute>"
" <attribute name='target' type='i'>2</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>Some Toggle</attribute>"
" <attribute name='action'>win.sometoggle</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Help</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_About Window</attribute>"
" <attribute name='action'>win.about</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_About App</attribute>"
" <attribute name='action'>app.about</attribute>"
" </item>"
" </section>"
" </submenu>"
" </menu>"
"</interface>";
try
{
m_refBuilder->add_from_string(ui_info);
}
catch (const Glib::Error& ex)
{
std::cerr << "Building menus failed: " << ex.what();
}
//Get the menubar and the app menu, and add them to the application:
auto gmenu = m_refBuilder->get_object<Gio::Menu>("menu-example");
if (!gmenu)
{
g_warning("GMenu not found");
}
else
{
set_menubar(gmenu);
}
}
void ExampleApplication::on_activate()
{
//std::cout << "debug1: " << G_STRFUNC << std::endl;
// The application has been started, so let's show a window.
// A real application might want to reuse this window in on_open(),
// when asked to open a file, if no changes have been made yet.
create_window();
}
void ExampleApplication::create_window()
{
auto win = new ExampleWindow();
//Make sure that the application runs for as long this window is still open:
add_window(*win);
//Delete the window when it is hidden.
//That's enough for this simple example.
win->signal_hide().connect([win]() { delete win; });
win->set_show_menubar();
win->set_visible(true);
}
void ExampleApplication::on_menu_file_new_generic()
{
std::cout << "A File|New menu item was selected." << std::endl;
}
void ExampleApplication::on_menu_file_quit()
{
std::cout << G_STRFUNC << std::endl;
quit(); // Not really necessary, when Gtk::Widget::set_visible(false) is called.
// Gio::Application::quit() will make Gio::Application::run() return,
// but it's a crude way of ending the program. The window is not removed
// from the application. Neither the window's nor the application's
// destructors will be called, because there will be remaining reference
// counts in both of them. If we want the destructors to be called, we
// must remove the window from the application. One way of doing this
// is to hide the window.
std::vector<Gtk::Window*> windows = get_windows();
if (windows.size() > 0)
windows[0]->set_visible(false); // In this simple case, we know there is only one window.
}
void ExampleApplication::on_menu_help_about()
{
std::cout << "Help|About App was selected." << std::endl;
}
File: examplewindow.cc
(For use with gtkmm 4)
#include "examplewindow.h"
#include <iostream>
ExampleWindow::ExampleWindow()
: Gtk::ApplicationWindow(),
m_Box(Gtk::Orientation::VERTICAL)
{
set_title("Main menu example");
set_default_size(300, 100);
// ExampleApplication displays the menubar. Other stuff, such as a toolbar,
// is put into the box.
set_child(m_Box);
// Create actions for menus and toolbars.
// We can use add_action() because Gtk::ApplicationWindow derives from Gio::ActionMap.
// This Action Map uses a "win." prefix for the actions.
// Therefore, for instance, "win.copy", is used in ExampleApplication::on_startup()
// to layout the menu.
//Edit menu:
add_action("copy", sigc::mem_fun(*this, &ExampleWindow::on_menu_others));
add_action("paste", sigc::mem_fun(*this, &ExampleWindow::on_menu_others));
add_action("something", sigc::mem_fun(*this, &ExampleWindow::on_menu_others));
//Choices menus, to demonstrate Radio items,
//using our convenience methods for string and int radio values:
m_refChoice = add_action_radio_string("choice",
sigc::mem_fun(*this, &ExampleWindow::on_menu_choices), "a");
m_refChoiceOther = add_action_radio_integer("choiceother",
sigc::mem_fun(*this, &ExampleWindow::on_menu_choices_other), 1);
m_refToggle = add_action_bool("sometoggle",
sigc::mem_fun(*this, &ExampleWindow::on_menu_toggle), false);
//Help menu:
add_action("about", sigc::mem_fun(*this, &ExampleWindow::on_menu_others));
//Create the toolbar and add it to a container widget:
m_refBuilder = Gtk::Builder::create();
Glib::ustring ui_info =
"<!-- Generated with glade 3.18.3 and then changed manually -->"
"<interface>"
" <object class='GtkBox' id='toolbar'>"
" <property name='can_focus'>False</property>"
" <child>"
" <object class='GtkButton' id='toolbutton_new'>"
" <property name='can_focus'>False</property>"
" <property name='tooltip_text' translatable='yes'>New Standard</property>"
" <property name='action_name'>app.newstandard</property>"
" <property name='icon_name'>document-new</property>"
" <property name='hexpand'>False</property>"
" <property name='vexpand'>False</property>"
" </object>"
" </child>"
" <child>"
" <object class='GtkButton' id='toolbutton_quit'>"
" <property name='can_focus'>False</property>"
" <property name='tooltip_text' translatable='yes'>Quit</property>"
" <property name='action_name'>app.quit</property>"
" <property name='icon_name'>application-exit</property>"
" <property name='hexpand'>False</property>"
" <property name='vexpand'>False</property>"
" </object>"
" </child>"
" </object>"
"</interface>";
try
{
m_refBuilder->add_from_string(ui_info);
}
catch (const Glib::Error& ex)
{
std::cerr << "Building toolbar failed: " << ex.what();
}
auto toolbar = m_refBuilder->get_widget<Gtk::Box>("toolbar");
if (!toolbar)
g_warning("toolbar not found");
else
m_Box.append(*toolbar);
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_menu_others()
{
std::cout << "A menu item was selected." << std::endl;
}
void ExampleWindow::on_menu_choices(const Glib::ustring& parameter)
{
//The radio action's state does not change automatically:
m_refChoice->change_state(parameter);
Glib::ustring message;
if (parameter == "a")
message = "Choice a was selected.";
else
message = "Choice b was selected.";
std::cout << message << std::endl;
}
void ExampleWindow::on_menu_choices_other(int parameter)
{
//The radio action's state does not change automatically:
m_refChoiceOther->change_state(parameter);
Glib::ustring message;
if (parameter == 1)
message = "Choice 1 was selected.";
else
message = "Choice 2 was selected.";
std::cout << message << std::endl;
}
void ExampleWindow::on_menu_toggle()
{
bool active = false;
m_refToggle->get_state(active);
//The toggle action's state does not change automatically:
active = !active;
m_refToggle->change_state(active);
Glib::ustring message;
if (active)
message = "Toggle is active.";
else
message = "Toggle is not active.";
std::cout << message << std::endl;
}
File: main.cc
(For use with gtkmm 4)
#include "exampleapplication.h"
int main(int argc, char* argv[])
{
auto application = ExampleApplication::create();
// Start the application, showing the initial window,
// and opening extra windows for any files that it is asked to open,
// for instance as a command-line parameter.
// run() will return when the last window has been closed by the user.
const int status = application->run(argc, argv);
return status;
}
This program contains a menubar and a toolbar.
A class is derived from Gtk::Window
.
File: examplewindow.h
(For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow(const Glib::RefPtr<Gtk::Application>& app);
virtual ~ExampleWindow();
private:
//Signal handlers:
//void on_action_file_new();
void on_action_file_quit();
void on_action_others();
void on_action_toggle();
//Child widgets:
Gtk::Box m_Box;
Glib::RefPtr<Gtk::Builder> m_refBuilder;
Glib::RefPtr<Gio::SimpleActionGroup> m_refActionGroup;
Glib::RefPtr<Gio::SimpleAction> m_refActionRain;
};
#endif //GTKMM_EXAMPLEWINDOW_H
File: examplewindow.cc
(For use with gtkmm 4)
#include "examplewindow.h"
#include <gtkmm.h>
#include <iostream>
ExampleWindow::ExampleWindow(const Glib::RefPtr<Gtk::Application>& app)
: m_Box(Gtk::Orientation::VERTICAL)
{
set_title("main_menu example");
set_default_size(200, 200);
set_child(m_Box); //We can put a MenuBar at the top of the box and other stuff below it.
//Define the actions:
m_refActionGroup = Gio::SimpleActionGroup::create();
// There are several ways of calling a function that takes a sigc::slot.
// If the slot function is very short, it might be easy to skip the on_xxx()
// method and put its contents directly in a lambda expression.
m_refActionGroup->add_action("new",
[] { std::cout << "A File|New menu item was selected.\n"; /* on_action_file_new() */});
// With sigc::mem_fun() or (for non-member functions and static member functions)
// sigc::ptr_fun(). The only way before C++11 introduced lambda expressions.
m_refActionGroup->add_action("open",
sigc::mem_fun(*this, &ExampleWindow::on_action_others) );
// With a lambda expression. Does not disconnect automatically when ExampleWindow
// is deleted, like sigc::mem_fun() does.
m_refActionRain = m_refActionGroup->add_action_bool("rain",
[this] { on_action_toggle(); }, false);
m_refActionGroup->add_action("quit",
sigc::mem_fun(*this, &ExampleWindow::on_action_file_quit) );
// With a lambda expression and sigc::track_obj() or sigc::track_object().
// Disconnects automatically like sigc::mem_fun().
#if SIGCXX_MINOR_VERSION >= 4
m_refActionGroup->add_action("cut",
sigc::track_object([this] { on_action_others(); }, *this));
#else
m_refActionGroup->add_action("cut",
sigc::track_obj([this] { on_action_others(); }, *this));
#endif
m_refActionGroup->add_action("copy",
sigc::mem_fun(*this, &ExampleWindow::on_action_others) );
m_refActionGroup->add_action("paste",
sigc::mem_fun(*this, &ExampleWindow::on_action_others) );
insert_action_group("example", m_refActionGroup);
//Define how the actions are presented in the menus and toolbars:
m_refBuilder = Gtk::Builder::create();
//Layout the actions in a menubar and toolbar:
const Glib::ustring ui_info =
"<interface>"
" <menu id='menubar'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_File</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_New</attribute>"
" <attribute name='action'>example.new</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Open</attribute>"
" <attribute name='action'>example.open</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>Rain</attribute>"
" <attribute name='action'>example.rain</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Quit</attribute>"
" <attribute name='action'>example.quit</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Edit</attribute>"
" <item>"
" <attribute name='label' translatable='yes'>_Cut</attribute>"
" <attribute name='action'>example.cut</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Copy</attribute>"
" <attribute name='action'>example.copy</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Paste</attribute>"
" <attribute name='action'>example.paste</attribute>"
" </item>"
" </submenu>"
" </menu>"
"</interface>";
// Set accelerator keys:
app->set_accel_for_action("example.new", "<Primary>n");
app->set_accel_for_action("example.open", "<Primary>o");
app->set_accel_for_action("example.quit", "<Primary>q");
app->set_accel_for_action("example.cut", "<Primary>x");
app->set_accel_for_action("example.copy", "<Primary>c");
app->set_accel_for_action("example.paste", "<Primary>v");
try
{
m_refBuilder->add_from_string(ui_info);
m_refBuilder->add_from_resource("/toolbar/toolbar.ui");
}
catch(const Glib::Error& ex)
{
std::cerr << "Building menus and toolbar failed: " << ex.what();
}
//Get the menubar:
auto gmenu = m_refBuilder->get_object<Gio::Menu>("menubar");
if (!gmenu)
g_warning("GMenu not found");
else
{
auto pMenuBar = Gtk::make_managed<Gtk::PopoverMenuBar>(gmenu);
//Add the PopoverMenuBar to the window:
m_Box.append(*pMenuBar);
}
//Get the toolbar and add it to a container widget:
auto toolbar = m_refBuilder->get_widget<Gtk::Box>("toolbar");
if (!toolbar)
g_warning("toolbar not found");
else
m_Box.append(*toolbar);
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_action_file_quit()
{
set_visible(false); //Closes the main window to stop the app->make_window_and_run().
}
//void ExampleWindow::on_action_file_new()
//{
// std::cout << "A File|New menu item was selected." << std::endl;
//}
void ExampleWindow::on_action_others()
{
std::cout << "A menu item was selected." << std::endl;
}
void ExampleWindow::on_action_toggle()
{
std::cout << "The toggle menu item was selected." << std::endl;
bool active = false;
m_refActionRain->get_state(active);
//The toggle action's state does not change automatically:
active = !active;
m_refActionRain->change_state(active);
Glib::ustring message;
if(active)
message = "Toggle is active.";
else
message = "Toggle is not active";
std::cout << message << std::endl;
}
File: main.cc
(For use with gtkmm 4)
#include <gtkmm.h>
#include "examplewindow.h"
int main(int argc, char* argv[])
{
auto app = Gtk::Application::create("org.gtkmm.example");
//Shows the window and returns when it is closed.
return app->make_window_and_run<ExampleWindow>(argc, argv, app);
}
File: toolbar.gresource.xml
(For use with gtkmm 4)
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/toolbar">
<file preprocess="xml-stripblanks">toolbar.ui</file>
<file>rain.png</file>
</gresource>
</gresources>
File: examplewindow.h
(For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
#include <memory>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow(const Glib::RefPtr<Gtk::Application>& app);
virtual ~ExampleWindow();
protected:
//Signal handlers:
void on_label_pressed(int n_press, double x, double y);
void on_menu_file_popup_generic();
//Child widgets:
Gtk::Box m_Box;
Gtk::Label m_Label;
Gtk::PopoverMenu m_MenuPopup;
Glib::RefPtr<Gtk::Builder> m_refBuilder;
Glib::RefPtr<Gtk::GestureClick> m_refGesture;
};
#endif //GTKMM_EXAMPLEWINDOW_H
File: examplewindow.cc
(For use with gtkmm 4)
#include "examplewindow.h"
#include <iostream>
ExampleWindow::ExampleWindow(const Glib::RefPtr<Gtk::Application>& app)
: m_Box(Gtk::Orientation::VERTICAL),
m_Label("Right-click to see the popup menu.")
{
set_title("popup example");
set_default_size(200, 200);
set_child(m_Box);
// Catch button_press events:
m_Box.append(m_Label);
m_Label.set_expand();
m_refGesture = Gtk::GestureClick::create();
m_refGesture->set_button(GDK_BUTTON_SECONDARY);
m_refGesture->signal_pressed().connect(
sigc::mem_fun(*this, &ExampleWindow::on_label_pressed));
m_Label.add_controller(m_refGesture);
//Create actions:
auto refActionGroup = Gio::SimpleActionGroup::create();
//File|New sub menu:
//These menu actions would normally already exist for a main menu, because a
//context menu should not normally contain menu items that are only available
//via a context menu.
refActionGroup->add_action("edit",
sigc::mem_fun(*this, &ExampleWindow::on_menu_file_popup_generic));
refActionGroup->add_action("process",
sigc::mem_fun(*this, &ExampleWindow::on_menu_file_popup_generic));
refActionGroup->add_action("remove",
sigc::mem_fun(*this, &ExampleWindow::on_menu_file_popup_generic));
insert_action_group("examplepopup", refActionGroup);
// Set accelerator keys:
app->set_accel_for_action("examplepopup.edit", "<Primary>e");
app->set_accel_for_action("examplepopup.process", "<Primary>p");
app->set_accel_for_action("examplepopup.remove", "<Primary>r");
m_refBuilder = Gtk::Builder::create();
//Layout the actions in a menubar and toolbar:
Glib::ustring ui_info =
"<interface>"
" <menu id='menu-examplepopup'>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>Edit</attribute>"
" <attribute name='action'>examplepopup.edit</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>Process</attribute>"
" <attribute name='action'>examplepopup.process</attribute>"
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>Remove</attribute>"
" <attribute name='action'>examplepopup.remove</attribute>"
" </item>"
" </section>"
" </menu>"
"</interface>";
try
{
m_refBuilder->add_from_string(ui_info);
}
catch(const Glib::Error& ex)
{
std::cerr << "building menus failed: " << ex.what();
}
//Get the menu:
auto gmenu = m_refBuilder->get_object<Gio::Menu>("menu-examplepopup");
if(!gmenu)
g_warning("GMenu not found");
m_MenuPopup.set_parent(m_Label);
m_MenuPopup.set_menu_model(gmenu);
m_MenuPopup.set_has_arrow(false);
}
ExampleWindow::~ExampleWindow()
{
m_MenuPopup.unparent();
}
void ExampleWindow::on_menu_file_popup_generic()
{
std::cout << "A popup menu item was selected." << std::endl;
}
void ExampleWindow::on_label_pressed(int /* n_press */, double x, double y)
{
const Gdk::Rectangle rect(x, y, 1, 1);
m_MenuPopup.set_pointing_to(rect);
m_MenuPopup.popup();
}
File: main.cc
(For use with gtkmm 4)
#include "examplewindow.h"
#include <gtkmm/application.h>
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create("org.gtkmm.example");
//Shows the window and returns when it is closed.
return app->make_window_and_run<ExampleWindow>(argc, argv, app);
}