This is a more complex example with two SignalListItemFactory
objects and their signal handlers. This example would be simpler without the
checkmark in the dropdown menu.
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();
~ExampleWindow() override;
protected:
// Signal handlers:
void on_setup_selected_item(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_bind_selected_item(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_setup_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_bind_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_unbind_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_selected_item_changed(const Glib::RefPtr<Gtk::ListItem>& list_item);
void on_dropdown_changed();
void create_model();
void liststore_add_item(const Glib::ustring& title, const Glib::ustring& icon,
const Glib::ustring& description);
// A Gio::ListStore item.
class ModelColumns : public Glib::Object
{
public:
Glib::ustring m_title;
Glib::ustring m_icon;
Glib::ustring m_description;
static Glib::RefPtr<ModelColumns> create(const Glib::ustring& title,
const Glib::ustring& icon, const Glib::ustring& description)
{
return Glib::make_refptr_for_instance<ModelColumns>(
new ModelColumns(title, icon, description));
}
protected:
ModelColumns(const Glib::ustring& title, const Glib::ustring& icon,
const Glib::ustring& description)
: m_title(title), m_icon(icon), m_description(description)
{}
}; // ModelColumns
// Child widget:
Gtk::DropDown m_DropDown;
Glib::RefPtr<Gio::ListStore<ModelColumns>> m_ListStore;
};
#endif //GTKMM_EXAMPLEWINDOW_H
File: examplewindow.cc
(For use with gtkmm 4)
#include "examplewindow.h"
#include <iostream>
ExampleWindow::ExampleWindow()
{
set_title("DropDown example");
// Add the DropDown to the window.
set_child(m_DropDown);
// Factory for presenting the selected item.
auto factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &ExampleWindow::on_setup_selected_item));
factory->signal_bind().connect(
sigc::mem_fun(*this, &ExampleWindow::on_bind_selected_item));
m_DropDown.set_factory(factory);
// Factory for presenting the items in the dropdown list.
factory = Gtk::SignalListItemFactory::create();
factory->signal_setup().connect(
sigc::mem_fun(*this, &ExampleWindow::on_setup_list_item));
factory->signal_bind().connect(
sigc::mem_fun(*this, &ExampleWindow::on_bind_list_item));
factory->signal_unbind().connect(
sigc::mem_fun(*this, &ExampleWindow::on_unbind_list_item));
m_DropDown.set_list_factory(factory);
// Create the model and fill it.
create_model();
m_DropDown.set_model(m_ListStore);
m_DropDown.set_selected(0);
// Connect signal handler:
m_DropDown.property_selected().signal_changed().connect(
sigc::mem_fun(*this, &ExampleWindow::on_dropdown_changed));
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_dropdown_changed()
{
const auto selected = m_DropDown.get_selected();
std::cout << "DropDown changed: Row=" << selected
<< ", Title=" << m_ListStore->get_item(selected)->m_title << std::endl;
}
void ExampleWindow::create_model()
{
m_ListStore = Gio::ListStore<ModelColumns>::create();
liststore_add_item("Digital Output", "audio-card-symbolic", "Built-in Audio");
liststore_add_item("Headphones", "audio-headphones-symbolic", "Built-in Audio");
liststore_add_item("Digital Output", "audio-card-symbolic", "Thinkpad Tunderbolt 3 Dock USB Audio");
liststore_add_item("Analog Output", "audio-card-symbolic", "Thinkpad Tunderbolt 3 Dock USB Audio");
}
void ExampleWindow::liststore_add_item(const Glib::ustring& title,
const Glib::ustring& icon, const Glib::ustring& description)
{
m_ListStore->append(ModelColumns::create(title, icon, description));
}
void ExampleWindow::on_setup_selected_item(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 10);
box->append(*Gtk::make_managed<Gtk::Image>());
box->append(*Gtk::make_managed<Gtk::Label>());
list_item->set_child(*box);
}
void ExampleWindow::on_bind_selected_item(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto col = std::dynamic_pointer_cast<ModelColumns>(list_item->get_item());
if (!col)
return;
auto box = dynamic_cast<Gtk::Box*>(list_item->get_child());
if (!box)
return;
auto image = dynamic_cast<Gtk::Image*>(box->get_first_child());
if (!image)
return;
image->set_from_icon_name(col->m_icon);
auto label = dynamic_cast<Gtk::Label*>(image->get_next_sibling());
if (!label)
return;
label->set_text(col->m_title);
}
void ExampleWindow::on_setup_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto hbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 10);
auto vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 2);
hbox->append(*Gtk::make_managed<Gtk::Image>());
hbox->append(*vbox);
auto title = Gtk::make_managed<Gtk::Label>();
title->set_xalign(0.0);
vbox->append(*title);
auto description = Gtk::make_managed<Gtk::Label>();
description->set_xalign(0.0);
description->add_css_class("dim-label");
vbox->append(*description);
auto checkmark = Gtk::make_managed<Gtk::Image>();
checkmark->set_from_icon_name("object-select-symbolic");
checkmark->set_visible(false);
hbox->append(*checkmark);
list_item->set_child(*hbox);
}
void ExampleWindow::on_bind_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto col = std::dynamic_pointer_cast<ModelColumns>(list_item->get_item());
if (!col)
return;
auto hbox = dynamic_cast<Gtk::Box*>(list_item->get_child());
if (!hbox)
return;
auto image = dynamic_cast<Gtk::Image*>(hbox->get_first_child());
if (!image)
return;
image->set_from_icon_name(col->m_icon);
auto vbox = dynamic_cast<Gtk::Box*>(image->get_next_sibling());
if (!vbox)
return;
auto title = dynamic_cast<Gtk::Label*>(vbox->get_first_child());
if (!title)
return;
title->set_text(col->m_title);
auto description = dynamic_cast<Gtk::Label*>(title->get_next_sibling());
if (!description)
return;
description->set_text(col->m_description);
auto connection = m_DropDown.property_selected_item().signal_changed().connect(
sigc::bind(sigc::mem_fun(*this, &ExampleWindow::on_selected_item_changed),
list_item));
list_item->set_data("connection", new sigc::connection(connection),
Glib::destroy_notify_delete<sigc::connection>);
on_selected_item_changed(list_item);
}
void ExampleWindow::on_unbind_list_item(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
if (auto connection = static_cast<sigc::connection*>(list_item->get_data("connection")))
{
connection->disconnect();
list_item->set_data("connection", nullptr);
}
}
void ExampleWindow::on_selected_item_changed(const Glib::RefPtr<Gtk::ListItem>& list_item)
{
auto hbox = dynamic_cast<Gtk::Box*>(list_item->get_child());
if (!hbox)
return;
auto checkmark = dynamic_cast<Gtk::Image*>(hbox->get_last_child());
if (!checkmark)
return;
checkmark->set_visible(m_DropDown.get_selected_item() == list_item->get_item());
}
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);
}