Examples
Some TreeView examples are shown here. There are more examples in the treeview directory in gtkmm-documentation's examples.
If neither ListStore nor TreeStore is suitable for your application, look at the custom TreeModel example. It shows how you can make your own implementation of the TreeModel interface.
- 10.8.1. ListStore
- 10.8.2. TreeStore
- 10.8.3. Células editáveis
- 10.8.4. Arrastar e soltar
- 10.8.5. Contexto de menu popup
10.8.1. ListStore
This example has a Gtk::TreeView widget, with a Gtk::ListStore model.
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(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); add(m_col_number); add(m_col_percentage);} Gtk::TreeModelColumn<unsigned int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; Gtk::TreeModelColumn<short> m_col_number; Gtk::TreeModelColumn<int> m_col_percentage; }; ModelColumns m_Columns; //Child widgets: Gtk::Box m_VBox; Gtk::ScrolledWindow m_ScrolledWindow; Gtk::TreeView m_TreeView; Glib::RefPtr<Gtk::ListStore> m_refTreeModel; Gtk::Box m_ButtonBox; Gtk::Button m_Button_Quit; }; #endif //GTKMM_EXAMPLEWINDOW_H
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); }
File: examplewindow.cc (For use with gtkmm 4)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_VBox(Gtk::Orientation::VERTICAL), m_Button_Quit("Quit") { set_title("Gtk::TreeView (ListStore) example"); set_default_size(400, 200); m_VBox.set_margin(5); set_child(m_VBox); //Add the TreeView, inside a ScrolledWindow, with the button underneath: m_ScrolledWindow.set_child(m_TreeView); //Only show the scrollbars when they are necessary: m_ScrolledWindow.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC); m_ScrolledWindow.set_expand(); m_VBox.append(m_ScrolledWindow); m_VBox.append(m_ButtonBox); m_ButtonBox.append(m_Button_Quit); m_ButtonBox.set_margin(5); m_Button_Quit.set_hexpand(true); m_Button_Quit.set_halign(Gtk::Align::END); m_Button_Quit.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); //Create the Tree model: m_refTreeModel = Gtk::ListStore::create(m_Columns); m_TreeView.set_model(m_refTreeModel); //Fill the TreeView's model auto row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 1; row[m_Columns.m_col_name] = "Billy Bob"; row[m_Columns.m_col_number] = 10; row[m_Columns.m_col_percentage] = 15; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 2; row[m_Columns.m_col_name] = "Joey Jojo"; row[m_Columns.m_col_number] = 20; row[m_Columns.m_col_percentage] = 40; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 3; row[m_Columns.m_col_name] = "Rob McRoberts"; row[m_Columns.m_col_number] = 30; row[m_Columns.m_col_percentage] = 70; //Add the TreeView's view columns: //This number will be shown with the default numeric formatting. m_TreeView.append_column("ID", m_Columns.m_col_id); m_TreeView.append_column("Name", m_Columns.m_col_name); m_TreeView.append_column_numeric("Formatted number", m_Columns.m_col_number, "%010d" /* 10 digits, using leading zeroes. */); //Display a progress bar instead of a decimal number: auto cell = Gtk::make_managed<Gtk::CellRendererProgress>(); int cols_count = m_TreeView.append_column("Some percentage", *cell); auto pColumn = m_TreeView.get_column(cols_count - 1); if(pColumn) { pColumn->add_attribute(cell->property_value(), m_Columns.m_col_percentage); } //Make all the columns reorderable: //This is not necessary, but it's nice to show the feature. //You can use TreeView::set_column_drag_function() to more //finely control column drag and drop. for(guint i = 0; i < 2; i++) { auto column = m_TreeView.get_column(i); column->set_reorderable(); } } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); }
10.8.2. TreeStore
This example is very similar to the ListStore example, but uses a Gtk::TreeStore model instead, and adds children to the rows.
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(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); void on_treeview_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); } Gtk::TreeModelColumn<int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; }; ModelColumns m_Columns; //Child widgets: Gtk::Box m_VBox; Gtk::ScrolledWindow m_ScrolledWindow; Gtk::TreeView m_TreeView; Glib::RefPtr<Gtk::TreeStore> m_refTreeModel; Gtk::Box m_ButtonBox; Gtk::Button m_Button_Quit; }; #endif //GTKMM_EXAMPLEWINDOW_H
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); }
File: examplewindow.cc (For use with gtkmm 4)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_VBox(Gtk::Orientation::VERTICAL), m_Button_Quit("Quit") { set_title("Gtk::TreeView (TreeStore) example"); set_default_size(400, 200); m_VBox.set_margin(5); set_child(m_VBox); //Add the TreeView, inside a ScrolledWindow, with the button underneath: m_ScrolledWindow.set_child(m_TreeView); //Only show the scrollbars when they are necessary: m_ScrolledWindow.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC); m_ScrolledWindow.set_expand(); m_VBox.append(m_ScrolledWindow); m_VBox.append(m_ButtonBox); m_ButtonBox.append(m_Button_Quit); m_ButtonBox.set_margin(5); m_Button_Quit.set_hexpand(true); m_Button_Quit.set_halign(Gtk::Align::END); m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); //Create the Tree model: m_refTreeModel = Gtk::TreeStore::create(m_Columns); m_TreeView.set_model(m_refTreeModel); //All the items to be reordered with drag-and-drop: m_TreeView.set_reorderable(); //Fill the TreeView's model auto row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 1; row[m_Columns.m_col_name] = "Billy Bob"; auto childrow = *(m_refTreeModel->append(row.children())); childrow[m_Columns.m_col_id] = 11; childrow[m_Columns.m_col_name] = "Billy Bob Junior"; childrow = *(m_refTreeModel->append(row.children())); childrow[m_Columns.m_col_id] = 12; childrow[m_Columns.m_col_name] = "Sue Bob"; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 2; row[m_Columns.m_col_name] = "Joey Jojo"; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 3; row[m_Columns.m_col_name] = "Rob McRoberts"; childrow = *(m_refTreeModel->append(row.children())); childrow[m_Columns.m_col_id] = 31; childrow[m_Columns.m_col_name] = "Xavier McRoberts"; //Add the TreeView's view columns: m_TreeView.append_column("ID", m_Columns.m_col_id); m_TreeView.append_column("Name", m_Columns.m_col_name); //Connect signal: m_TreeView.signal_row_activated().connect(sigc::mem_fun(*this, &ExampleWindow::on_treeview_row_activated) ); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); } void ExampleWindow::on_treeview_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* /* column */) { const auto iter = m_refTreeModel->get_iter(path); if(iter) { const auto row = *iter; std::cout << "Row activated: ID=" << row[m_Columns.m_col_id] << ", Name=" << row[m_Columns.m_col_name] << std::endl; } }
10.8.3. Células editáveis
This example is identical to the ListStore example, but it uses TreeView::append_column_editable() instead of TreeView::append_column().
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(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); void treeviewcolumn_validated_on_cell_data(Gtk::CellRenderer* renderer, const Gtk::TreeModel::const_iterator& iter); void cellrenderer_validated_on_editing_started(Gtk::CellEditable* cell_editable, const Glib::ustring& path); void cellrenderer_validated_on_edited(const Glib::ustring& path_string, const Glib::ustring& new_text); void on_message_response(int response_id, Gtk::MessageDialog* dialog); //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); add(m_col_foo); add(m_col_number); add(m_col_number_validated); } Gtk::TreeModelColumn<unsigned int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; Gtk::TreeModelColumn<bool> m_col_foo; Gtk::TreeModelColumn<int> m_col_number; Gtk::TreeModelColumn<int> m_col_number_validated; }; ModelColumns m_Columns; //Child widgets: Gtk::Box m_VBox; Gtk::ScrolledWindow m_ScrolledWindow; Gtk::TreeView m_TreeView; Glib::RefPtr<Gtk::ListStore> m_refTreeModel; Gtk::Box m_ButtonBox; Gtk::Button m_Button_Quit; //For the validated column: //You could also use a CellRendererSpin or a CellRendererProgress: Gtk::CellRendererText m_cellrenderer_validated; Gtk::TreeView::Column m_treeviewcolumn_validated; bool m_validate_retry; Glib::ustring m_invalid_text_for_retry; }; #endif //GTKMM_EXAMPLEWINDOW_H
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); }
File: examplewindow.cc (For use with gtkmm 4)
#include <iostream> #include <cstdio> #include <cstdlib> #include "examplewindow.h" using std::sprintf; using std::strtol; ExampleWindow::ExampleWindow() : m_VBox(Gtk::Orientation::VERTICAL), m_Button_Quit("Quit"), m_validate_retry(false) { set_title("Gtk::TreeView Editable Cells example"); set_default_size(400, 200); m_VBox.set_margin(5); set_child(m_VBox); //Add the TreeView, inside a ScrolledWindow, with the button underneath: m_ScrolledWindow.set_child(m_TreeView); //Only show the scrollbars when they are necessary: m_ScrolledWindow.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC); m_ScrolledWindow.set_expand(); m_VBox.append(m_ScrolledWindow); m_VBox.append(m_ButtonBox); m_ButtonBox.append(m_Button_Quit); m_ButtonBox.set_margin(5); m_Button_Quit.set_hexpand(true); m_Button_Quit.set_halign(Gtk::Align::END); m_Button_Quit.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); //Create the Tree model: m_refTreeModel = Gtk::ListStore::create(m_Columns); m_TreeView.set_model(m_refTreeModel); //Fill the TreeView's model auto row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 1; row[m_Columns.m_col_name] = "Billy Bob"; row[m_Columns.m_col_foo] = true; row[m_Columns.m_col_number] = 10; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 2; row[m_Columns.m_col_name] = "Joey Jojo"; row[m_Columns.m_col_foo] = true; row[m_Columns.m_col_number] = 20; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 3; row[m_Columns.m_col_name] = "Rob McRoberts"; row[m_Columns.m_col_foo] = false; row[m_Columns.m_col_number] = 30; //Add the TreeView's view columns: //We use the *_editable convenience methods for most of these, //because the default functionality is enough: m_TreeView.append_column_editable("ID", m_Columns.m_col_id); m_TreeView.append_column_editable("Name", m_Columns.m_col_name); m_TreeView.append_column_editable("foo", m_Columns.m_col_foo); m_TreeView.append_column_numeric_editable("foo", m_Columns.m_col_number, "%010d"); //For this column, we create the CellRenderer ourselves, and connect our own //signal handlers, so that we can validate the data that the user enters, and //control how it is displayed. m_treeviewcolumn_validated.set_title("validated (<10)"); m_treeviewcolumn_validated.pack_start(m_cellrenderer_validated); m_TreeView.append_column(m_treeviewcolumn_validated); //Tell the view column how to render the model values: m_treeviewcolumn_validated.set_cell_data_func(m_cellrenderer_validated, sigc::mem_fun(*this, &ExampleWindow::treeviewcolumn_validated_on_cell_data) ); //Make the CellRenderer editable, and handle its editing signals: m_cellrenderer_validated.property_editable() = true; m_cellrenderer_validated.signal_editing_started().connect( sigc::mem_fun(*this, &ExampleWindow::cellrenderer_validated_on_editing_started) ); m_cellrenderer_validated.signal_edited().connect( sigc::mem_fun(*this, &ExampleWindow::cellrenderer_validated_on_edited) ); //If this was a CellRendererSpin then you would have to set the adjustment: //m_cellrenderer_validated.property_adjustment() = m_spin_adjustment; } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); } void ExampleWindow::treeviewcolumn_validated_on_cell_data( Gtk::CellRenderer* /* renderer */, const Gtk::TreeModel::const_iterator& iter) { //Get the value from the model and show it appropriately in the view: if(iter) { const auto row = *iter; int model_value = row[m_Columns.m_col_number_validated]; //This is just an example. //In this case, it would be easier to use append_column_editable() or //append_column_numeric_editable() char buffer[32]; sprintf(buffer, "%d", model_value); auto view_text = buffer; m_cellrenderer_validated.property_text() = view_text; } } void ExampleWindow::cellrenderer_validated_on_editing_started( Gtk::CellEditable* cell_editable, const Glib::ustring& /* path */) { //Start editing with previously-entered (but invalid) text, //if we are allowing the user to correct some invalid data. if(m_validate_retry) { //This is the CellEditable inside the CellRenderer. auto celleditable_validated = cell_editable; //It's usually an Entry, at least for a CellRendererText: auto pEntry = dynamic_cast<Gtk::Entry*>(celleditable_validated); if(pEntry) { pEntry->set_text(m_invalid_text_for_retry); m_validate_retry = false; m_invalid_text_for_retry.clear(); } } } void ExampleWindow::cellrenderer_validated_on_edited( const Glib::ustring& path_string, const Glib::ustring& new_text) { Gtk::TreePath path(path_string); //Convert the inputed text to an integer, as needed by our model column: char* pchEnd = nullptr; int new_value = strtol(new_text.c_str(), &pchEnd, 10); if(new_value >= 10) { //Prevent entry of numbers higher than 10. //Tell the user: auto dialog = new Gtk::MessageDialog(*this, "The number must be less than 10. Please try again.", false, Gtk::MessageType::ERROR, Gtk::ButtonsType::OK, true /* modal */); dialog->signal_response().connect(sigc::bind( sigc::mem_fun(*this, &ExampleWindow::on_message_response), dialog)); dialog->show(); //Start editing again, with the bad text, so that the user can correct it. //A real application should probably allow the user to revert to the //previous text. //Set the text to be used in the start_editing signal handler: m_invalid_text_for_retry = new_text; m_validate_retry = true; //Start editing again, when the message dialog has been closed: m_TreeView.set_cursor(path, m_treeviewcolumn_validated, m_cellrenderer_validated, true /* start_editing */); } else { //Get the row from the path: auto iter = m_refTreeModel->get_iter(path); if(iter) { auto row = *iter; //Put the new value in the model: row[m_Columns.m_col_number_validated] = new_value; } } } void ExampleWindow::on_message_response(int /* response_id */, Gtk::MessageDialog* dialog) { delete dialog; }
10.8.4. Arrastar e soltar
This example is much like the TreeStore example, but has 2 extra columns to indicate whether the row can be dragged, and whether it can receive drag-and-dropped rows. It uses a derived Gtk::TreeStore which overrides the virtual functions as described in the TreeView Drag and Drop section.
File: examplewindow.h (For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> #include "treemodel_dnd.h" class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); //Child widgets: Gtk::Box m_VBox; Gtk::ScrolledWindow m_ScrolledWindow; Gtk::TreeView m_TreeView; Glib::RefPtr<TreeModel_Dnd> m_refTreeModel; Gtk::Box m_ButtonBox; Gtk::Button m_Button_Quit; }; #endif //GTKMM_EXAMPLEWINDOW_H
File: treemodel_dnd.h (For use with gtkmm 4)
#ifndef GTKMM_EXAMPLE_TREEMODEL_DND_H #define GTKMM_EXAMPLE_TREEMODEL_DND_H #include <gtkmm.h> class TreeModel_Dnd : public Gtk::TreeStore { protected: TreeModel_Dnd(); public: //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); add(m_col_draggable); add(m_col_receivesdrags); } Gtk::TreeModelColumn<int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; Gtk::TreeModelColumn<bool> m_col_draggable; Gtk::TreeModelColumn<bool> m_col_receivesdrags; }; ModelColumns m_Columns; static Glib::RefPtr<TreeModel_Dnd> create(); protected: //Overridden virtual functions: bool row_draggable_vfunc(const Gtk::TreeModel::Path& path) const override; bool row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Glib::ValueBase& value) const override; }; #endif //GTKMM_EXAMPLE_TREEMODEL_DND_H
File: treemodel_dnd.cc (For use with gtkmm 4)
#include "treemodel_dnd.h" #include <iostream> TreeModel_Dnd::TreeModel_Dnd() { //We can't just call Gtk::TreeModel(m_Columns) in the initializer list //because m_Columns does not exist when the base class constructor runs. //And we can't have a static m_Columns instance, because that would be //instantiated before the gtkmm type system. //So, we use this method, which should only be used just after creation: set_column_types(m_Columns); } Glib::RefPtr<TreeModel_Dnd> TreeModel_Dnd::create() { return Glib::make_refptr_for_instance<TreeModel_Dnd>( new TreeModel_Dnd() ); } bool TreeModel_Dnd::row_draggable_vfunc(const Gtk::TreeModel::Path& path) const { // Make the value of the "draggable" column determine whether this row can // be dragged: const const_iterator iter = get_iter(path); if(iter) { ConstRow row = *iter; bool is_draggable = row[m_Columns.m_col_draggable]; return is_draggable; } return Gtk::TreeStore::row_draggable_vfunc(path); } bool TreeModel_Dnd::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Glib::ValueBase& value) const { //Make the value of the "receives drags" column determine whether a row can be //dragged into it: //dest is the path that the row would have after it has been dropped: //But in this case we are more interested in the parent row: auto dest_parent = dest; bool dest_is_not_top_level = dest_parent.up(); if(!dest_is_not_top_level || dest_parent.empty()) { //The user wants to move something to the top-level. //Let's always allow that. } else { //Get an iterator for the row at this path: const const_iterator iter_dest_parent = get_iter(dest_parent); if(iter_dest_parent) { ConstRow row = *iter_dest_parent; bool receives_drags = row[m_Columns.m_col_receivesdrags]; return receives_drags; } } // You could also examine the row being dragged (via value) // if you must look at both rows to see whether a drop should be allowed. // You could use // Glib::RefPtr<const Gtk::TreeModel> model_dragged_row; // Gtk::TreeModel::Path path_dragged_row; // Gtk::TreeModel::Path::get_row_drag_data(value, // model_dragged_row, path_dragged_row); return Gtk::TreeStore::row_drop_possible_vfunc(dest, value); }
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); }
File: examplewindow.cc (For use with gtkmm 4)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_VBox(Gtk::Orientation::VERTICAL), m_Button_Quit("_Quit", true) { set_title("Gtk::TreeView (Drag and Drop) example"); set_default_size(400, 200); m_VBox.set_margin(5); set_child(m_VBox); //Add the TreeView, inside a ScrolledWindow, with the button underneath: m_ScrolledWindow.set_child(m_TreeView); //Only show the scrollbars when they are necessary: m_ScrolledWindow.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC); m_ScrolledWindow.set_expand(); m_VBox.append(m_ScrolledWindow); m_VBox.append(m_ButtonBox); m_ButtonBox.append(m_Button_Quit); m_ButtonBox.set_margin(5); m_Button_Quit.set_hexpand(true); m_Button_Quit.set_halign(Gtk::Align::END); m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); //Create the Tree model: //Use our derived model, which overrides some Gtk::TreeDragDest and //Gtk::TreeDragSource virtual functions: //The columns are declared in the overridden TreeModel. m_refTreeModel = TreeModel_Dnd::create(); m_TreeView.set_model(m_refTreeModel); //Enable Drag-and-Drop of TreeView rows: //See also the derived TreeModel's *_vfunc overrides. m_TreeView.enable_model_drag_source(); m_TreeView.enable_model_drag_dest(); //Fill the TreeView's model auto row = *(m_refTreeModel->append()); row[m_refTreeModel->m_Columns.m_col_id] = 1; row[m_refTreeModel->m_Columns.m_col_name] = "Billy Bob"; row[m_refTreeModel->m_Columns.m_col_draggable] = true; row[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; auto childrow = *(m_refTreeModel->append(row.children())); childrow[m_refTreeModel->m_Columns.m_col_id] = 11; childrow[m_refTreeModel->m_Columns.m_col_name] = "Billy Bob Junior"; childrow[m_refTreeModel->m_Columns.m_col_draggable] = true; childrow[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; childrow = *(m_refTreeModel->append(row.children())); childrow[m_refTreeModel->m_Columns.m_col_id] = 12; childrow[m_refTreeModel->m_Columns.m_col_name] = "Sue Bob"; childrow[m_refTreeModel->m_Columns.m_col_draggable] = true; childrow[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; row = *(m_refTreeModel->append()); row[m_refTreeModel->m_Columns.m_col_id] = 2; row[m_refTreeModel->m_Columns.m_col_name] = "Joey Jojo"; row[m_refTreeModel->m_Columns.m_col_draggable] = true; row[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; row = *(m_refTreeModel->append()); row[m_refTreeModel->m_Columns.m_col_id] = 3; row[m_refTreeModel->m_Columns.m_col_name] = "Rob McRoberts"; row[m_refTreeModel->m_Columns.m_col_draggable] = true; row[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; childrow = *(m_refTreeModel->append(row.children())); childrow[m_refTreeModel->m_Columns.m_col_id] = 31; childrow[m_refTreeModel->m_Columns.m_col_name] = "Xavier McRoberts"; childrow[m_refTreeModel->m_Columns.m_col_draggable] = true; childrow[m_refTreeModel->m_Columns.m_col_receivesdrags] = true; //Add the TreeView's view columns: m_TreeView.append_column("ID", m_refTreeModel->m_Columns.m_col_id); m_TreeView.append_column("Name", m_refTreeModel->m_Columns.m_col_name); m_TreeView.append_column_editable("Draggable", m_refTreeModel->m_Columns.m_col_draggable); m_TreeView.append_column_editable("Receives Drags", m_refTreeModel->m_Columns.m_col_receivesdrags); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); }
10.8.5. Contexto de menu popup
This example is much like the ListStore example, but derives a custom TreeView in order to override the button_press_event, and also to encapsulate the tree model code in our derived class. See the TreeView Popup Context Menu section.
File: examplewindow.h (For use with gtkmm 4)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> #include "treeview_withpopup.h" class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); //Child widgets: Gtk::Box m_VBox; Gtk::ScrolledWindow m_ScrolledWindow; TreeView_WithPopup m_TreeView; Gtk::Box m_ButtonBox; Gtk::Button m_Button_Quit; }; #endif //GTKMM_EXAMPLEWINDOW_H
File: treeview_withpopup.h (For use with gtkmm 4)
#ifndef GTKMM_EXAMPLE_TREEVIEW_WITHPOPUP_H #define GTKMM_EXAMPLE_TREEVIEW_WITHPOPUP_H #include <gtkmm.h> class TreeView_WithPopup : public Gtk::TreeView { public: TreeView_WithPopup(); virtual ~TreeView_WithPopup(); protected: // Signal handler for showing popup menu: void on_popup_button_pressed(int n_press, double x, double y); //Signal handler for popup menu items: void on_menu_file_popup_generic(); //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); } Gtk::TreeModelColumn<unsigned int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; }; ModelColumns m_Columns; //The Tree model: Glib::RefPtr<Gtk::ListStore> m_refTreeModel; Gtk::PopoverMenu m_MenuPopup; }; #endif //GTKMM_EXAMPLE_TREEVIEW_WITHPOPUP_H
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); }
File: examplewindow.cc (For use with gtkmm 4)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_VBox(Gtk::Orientation::VERTICAL), m_Button_Quit("Quit") { set_title("Gtk::TreeView (ListStore) example"); set_default_size(400, 200); m_VBox.set_margin(5); set_child(m_VBox); //Add the TreeView, inside a ScrolledWindow, with the button underneath: m_ScrolledWindow.set_child(m_TreeView); //Only show the scrollbars when they are necessary: m_ScrolledWindow.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC); m_ScrolledWindow.set_expand(); m_VBox.append(m_ScrolledWindow); m_VBox.append(m_ButtonBox); m_ButtonBox.append(m_Button_Quit); m_ButtonBox.set_margin(5); m_Button_Quit.set_hexpand(true); m_Button_Quit.set_halign(Gtk::Align::END); m_Button_Quit.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); }
File: treeview_withpopup.cc (For use with gtkmm 4)
#include "treeview_withpopup.h" #include <iostream> TreeView_WithPopup::TreeView_WithPopup() { //Create the Tree model: m_refTreeModel = Gtk::ListStore::create(m_Columns); set_model(m_refTreeModel); //Fill the TreeView's model auto row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 1; row[m_Columns.m_col_name] = "right-click on this"; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 2; row[m_Columns.m_col_name] = "or this"; row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = 3; row[m_Columns.m_col_name] = "or this, for a popup context menu"; //Add the TreeView's view columns: append_column("ID", m_Columns.m_col_id); append_column("Name", m_Columns.m_col_name); // Catch button press events: auto refGesture = Gtk::GestureClick::create(); refGesture->set_button(GDK_BUTTON_SECONDARY); refGesture->signal_pressed().connect( sigc::mem_fun(*this, &TreeView_WithPopup::on_popup_button_pressed)); add_controller(refGesture); // Fill popup menu: auto gmenu = Gio::Menu::create(); gmenu->append("_Edit", "popup.edit"); gmenu->append("_Process", "popup.process"); gmenu->append("_Remove", "popup.remove"); m_MenuPopup.set_parent(*this); m_MenuPopup.set_menu_model(gmenu); m_MenuPopup.set_has_arrow(false); // Create actions: auto refActionGroup = Gio::SimpleActionGroup::create(); refActionGroup->add_action("edit", sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic)); refActionGroup->add_action("process", sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic)); refActionGroup->add_action("remove", sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic)); insert_action_group("popup", refActionGroup); } TreeView_WithPopup::~TreeView_WithPopup() { } void TreeView_WithPopup::on_popup_button_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(); } void TreeView_WithPopup::on_menu_file_popup_generic() { std::cout << "A popup menu item was selected." << std::endl; auto refSelection = get_selection(); if(refSelection) { auto iter = refSelection->get_selected(); if(iter) { int id = (*iter)[m_Columns.m_col_id]; std::cout << " Selected ID=" << id << std::endl; } } }