Examples
| Chapter 8. The TreeView widget |

## Examples

### ListStore

This example has a `Gtk::TreeView` widget, with a `Gtk::ListStore` model.

Figure 8.3. TreeView - ListStore

Source Code

File: `examplewindow.h`

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();
      virtual ~ExampleWindow();

    protected:
      //Signal handlers:
      virtual 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::VBox m_VBox;

      Gtk::ScrolledWindow m_ScrolledWindow;
      Gtk::TreeView m_TreeView;
      Glib::RefPtr<Gtk::ListStore> m_refTreeModel;

      Gtk::HButtonBox m_ButtonBox;
      Gtk::Button m_Button_Quit;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `examplewindow.cc`

    #include <iostream>
    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    : m_Button_Quit("Quit")
    {
      set_title("Gtk::TreeView (ListStore) example");
      set_border_width(5);
      set_default_size(400, 200);

      add(m_VBox);

      //Add the TreeView, inside a ScrolledWindow, with the button underneath:
      m_ScrolledWindow.add(m_TreeView);

      //Only show the scrollbars when they are necessary:
      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      m_VBox.pack_start(m_ScrolledWindow);
      m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

      m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
      m_ButtonBox.set_border_width(5);
      m_ButtonBox.set_layout(Gtk::BUTTONBOX_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
      Gtk::TreeModel::Row 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:
      m_TreeView.append_column("ID", m_Columns.m_col_id); //This number will be shown with the default numeric formatting.
      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:
      Gtk::CellRendererProgress* cell = new Gtk::CellRendererProgress;
      int cols_count = m_TreeView.append_column("Some percentage", *cell);
      Gtk::TreeViewColumn* pColumn = m_TreeView.get_column(cols_count - 1);
      if(pColumn)
      {
    #ifdef GLIBMM_PROPERTIES_ENABLED
        pColumn->add_attribute(cell->property_value(), m_Columns.m_col_percentage);
    #else
        pColumn->add_attribute(*cell, "value", m_Columns.m_col_percentage);
    #endif
      }

      //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++)
      {
        Gtk::TreeView::Column* pColumn = m_TreeView.get_column(i);
        pColumn->set_reorderable();
      }

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_quit()
    {
      hide();
    }

File: `main.cc`

    #include <gtkmm/main.h>
    #include "examplewindow.h"

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      Gtk::Main::run(window); //Shows the window and returns when it is closed.

      return 0;
    }

### TreeStore

This example is very similar to the ListStore example, but uses a `Gtk::TreeStore` model instead, and adds children to the rows.

Figure 8.4. TreeView - TreeStore

Source Code

File: `examplewindow.h`

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();
      virtual ~ExampleWindow();

    protected:
      //Signal handlers:
      virtual void on_button_quit();
      virtual 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::VBox m_VBox;

      Gtk::ScrolledWindow m_ScrolledWindow;
      Gtk::TreeView m_TreeView;
      Glib::RefPtr<Gtk::TreeStore> m_refTreeModel;

      Gtk::HButtonBox m_ButtonBox;
      Gtk::Button m_Button_Quit;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `examplewindow.cc`

    #include <iostream>
    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    : m_Button_Quit("Quit")
    {
      set_title("Gtk::TreeView (TreeStore) example");
      set_border_width(5);
      set_default_size(400, 200);

      add(m_VBox);

      //Add the TreeView, inside a ScrolledWindow, with the button underneath:
      m_ScrolledWindow.add(m_TreeView);

      //Only show the scrollbars when they are necessary:
      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      m_VBox.pack_start(m_ScrolledWindow);
      m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

      m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
      m_ButtonBox.set_border_width(5);
      m_ButtonBox.set_layout(Gtk::BUTTONBOX_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
      Gtk::TreeModel::Row row = *(m_refTreeModel->append());
      row[m_Columns.m_col_id] = 1;
      row[m_Columns.m_col_name] = "Billy Bob";

      Gtk::TreeModel::Row 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) );

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_quit()
    {
      hide();
    }

    void ExampleWindow::on_treeview_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* /* column */)
    {
      Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
      if(iter)
      {
        Gtk::TreeModel::Row row = *iter;
        std::cout << "Row activated: ID=" << row[m_Columns.m_col_id] << ", Name=" << row[m_Columns.m_col_name] << std::endl;
      }
    }

File: `main.cc`

    #include <gtkmm/main.h>
    #include "examplewindow.h"

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      Gtk::Main::run(window); //Shows the window and returns when it is closed.

      return 0;
    }

### Editable Cells

This example is identical to the ListStore example, but it uses `TreeView::append_column_editable()` instead of `TreeView::append_column()`.

Figure 8.5. TreeView - Editable Cells

Source Code

File: `examplewindow.h`

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();
      virtual ~ExampleWindow();

    protected:
      //Signal handlers:
      virtual void on_button_quit();

      virtual void treeviewcolumn_validated_on_cell_data(Gtk::CellRenderer* renderer, const Gtk::TreeModel::iterator& iter);
      virtual void cellrenderer_validated_on_editing_started(Gtk::CellEditable* cell_editable, const Glib::ustring& path);
      virtual void cellrenderer_validated_on_edited(const Glib::ustring& path_string, const Glib::ustring& new_text);

      //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::VBox m_VBox;

      Gtk::ScrolledWindow m_ScrolledWindow;
      Gtk::TreeView m_TreeView;
      Glib::RefPtr<Gtk::ListStore> m_refTreeModel;

      Gtk::HButtonBox m_ButtonBox;
      Gtk::Button m_Button_Quit;

      //For the validated column:
      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: `examplewindow.cc`

    #include <iostream>
    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    : m_Button_Quit("Quit"),
      m_validate_retry(false)
    {
      set_title("Gtk::TreeView Editable Cells example");
      set_border_width(5);
      set_default_size(400, 200);

      add(m_VBox);

      //Add the TreeView, inside a ScrolledWindow, with the button underneath:
      m_ScrolledWindow.add(m_TreeView);

      //Only show the scrollbars when they are necessary:
      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      m_VBox.pack_start(m_ScrolledWindow);
      m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

      m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
      m_ButtonBox.set_border_width(5);
      m_ButtonBox.set_layout(Gtk::BUTTONBOX_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
      Gtk::TreeModel::Row 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:
    #ifdef GLIBMM_PROPERTIES_ENABLED
      m_cellrenderer_validated.property_editable() = true;
    #else
      m_cellrenderer_validated.set_property("editable", true);
    #endif

      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) );

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_quit()
    {
      hide();
    }

    void ExampleWindow::treeviewcolumn_validated_on_cell_data(Gtk::CellRenderer* /* renderer */, const Gtk::TreeModel::iterator& iter)
    {
      //Get the value from the model and show it appropriately in the view:
      if(iter)
      {
        Gtk::TreeModel::Row 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);

        Glib::ustring view_text = buffer;
    #ifdef GLIBMM_PROPERTIES_ENABLED
        m_cellrenderer_validated.property_text() = view_text;
    #else
        m_cellrenderer_validated.set_property("text", view_text);
    #endif
      }
    }

    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.
        Gtk::CellEditable* celleditable_validated = cell_editable;

        //It's usually an Entry, at least for a CellRendererText:
        Gtk::Entry* 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 = 0;
      int new_value = strtol(new_text.c_str(), &pchEnd, 10);

      if(new_value > 10)
      {
        //Prevent entry of numbers higher than 10.

        //Tell the user:
        Gtk::MessageDialog dialog(*this, "The number must be less than 10. Please try again.", false, Gtk::MESSAGE_ERROR);
        dialog.run();

        //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:
        m_TreeView.set_cursor(path, m_treeviewcolumn_validated, m_cellrenderer_validated, true /* start_editing */);
      }
      else
      {
        //Get the row from the path:
        Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
        if(iter)
        {
          Gtk::TreeModel::Row row = *iter;

          //Put the new value in the model:
          row[m_Columns.m_col_number_validated] = new_value;
        }
      }
    }

File: `main.cc`

    #include <gtkmm/main.h>
    #include "examplewindow.h"

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      Gtk::Main::run(window); //Shows the window and returns when it is closed.

      return 0;
    }

### Drag and Drop

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..

Figure 8.6. TreeView - Drag And Drop

Source Code

File: `examplewindow.h`

    #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:
      virtual void on_button_quit();

      //Child widgets:
      Gtk::VBox m_VBox;

      Gtk::ScrolledWindow m_ScrolledWindow;
      Gtk::TreeView m_TreeView;
      Glib::RefPtr<TreeModel_Dnd> m_refTreeModel;

      Gtk::HButtonBox m_ButtonBox;
      Gtk::Button m_Button_Quit;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `treemodel_dnd.h`

    #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:
      virtual bool row_draggable_vfunc(const Gtk::TreeModel::Path& path) const;
      virtual bool row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) const;

    };

    #endif //GTKMM_EXAMPLE_TREEMODEL_DND_H

File: `examplewindow.cc`

    #include <iostream>
    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    : m_Button_Quit(Gtk::Stock::QUIT)
    {
      set_title("Gtk::TreeView (Drag and Drop) example");
      set_border_width(5);
      set_default_size(400, 200);

      add(m_VBox);

      //Add the TreeView, inside a ScrolledWindow, with the button underneath:
      m_ScrolledWindow.add(m_TreeView);

      //Only show the scrollbars when they are necessary:
      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      m_VBox.pack_start(m_ScrolledWindow);
      m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

      m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
      m_ButtonBox.set_border_width(5);
      m_ButtonBox.set_layout(Gtk::BUTTONBOX_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:
      m_refTreeModel = TreeModel_Dnd::create(); //The columns are declared in the overridden TreeModel.
      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
      Gtk::TreeModel::Row 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;

      Gtk::TreeModel::Row 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);

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_quit()
    {
      hide();
    }

File: `main.cc`

    #include <gtkmm/main.h>
    #include "examplewindow.h"

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      Gtk::Main::run(window); //Shows the window and returns when it is closed.

      return 0;
    }

File: `treemodel_dnd.cc`

    #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::RefPtr<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:

      TreeModel_Dnd* unconstThis = const_cast<TreeModel_Dnd*>(this); //TODO: Add a const version of get_iter to TreeModel:
      const_iterator iter = unconstThis->get_iter(path);
      //const_iterator iter = get_iter(path);
      if(iter)
      {
        Row row = *iter;
        bool is_draggable = row[m_Columns.m_col_draggable];
        return is_draggable;
      }

    #ifdef GLIBMM_VFUNCS_ENABLED
      return Gtk::TreeStore::row_draggable_vfunc(path);
    #else
      return false;
    #endif
    }

    bool TreeModel_Dnd::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) 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:
      Gtk::TreeModel::Path 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:
        //We must unconst this. This should not be necessary with a future version of gtkmm.
        TreeModel_Dnd* unconstThis = const_cast<TreeModel_Dnd*>(this); //TODO: Add a const version of get_iter to TreeModel:
        const_iterator iter_dest_parent = unconstThis->get_iter(dest_parent);
        //const_iterator iter_dest_parent = get_iter(dest);
        if(iter_dest_parent)
        {
          Row 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 selection_data)
      //if you must look at both rows to see whether a drop should be allowed.
      //You could use
      //TODO: Add const version of get_from_selection_data(): Glib::RefPtr<const Gtk::TreeModel> refThis = Glib::RefPtr<const Gtk::TreeModel>(this);
      //Glib::RefPtr<Gtk::TreeModel> refThis = Glib::RefPtr<Gtk::TreeModel>(const_cast<TreeModel_Dnd*>(this));
      //refThis->reference(); //, true /* take_copy */)
      //Gtk::TreeModel::Path path_dragged_row;
      //Gtk::TreeModel::Path::get_from_selection_data(selection_data, refThis, path_dragged_row);

    #ifdef GLIBMM_VFUNCS_ENABLED
      return Gtk::TreeStore::row_drop_possible_vfunc(dest, selection_data);
    #else
      return false;
    #endif
    }

### Popup Context Menu

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.

Figure 8.7. TreeView - Popup Context Menu

Source Code

File: `examplewindow.h`

    #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:
      virtual void on_button_quit();

      //Child widgets:
      Gtk::VBox m_VBox;

      Gtk::ScrolledWindow m_ScrolledWindow;
      TreeView_WithPopup m_TreeView;

      Gtk::HButtonBox m_ButtonBox;
      Gtk::Button m_Button_Quit;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `treeview_withpopup.h`

    #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:
      // Override Signal handler:
      // Alternatively, use signal_button_press_event().connect_notify()
      virtual bool on_button_press_event(GdkEventButton *ev);

      //Signal handler for popup menu items:
      virtual 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::Menu m_Menu_Popup;
    };

    #endif //GTKMM_EXAMPLE_TREEVIEW_WITHPOPUP_H

File: `examplewindow.cc`

    #include <iostream>
    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    : m_Button_Quit("Quit")
    {
      set_title("Gtk::TreeView (ListStore) example");
      set_border_width(5);
      set_default_size(400, 200);

      add(m_VBox);

      //Add the TreeView, inside a ScrolledWindow, with the button underneath:
      m_ScrolledWindow.add(m_TreeView);

      //Only show the scrollbars when they are necessary:
      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      m_VBox.pack_start(m_ScrolledWindow);
      m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

      m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
      m_ButtonBox.set_border_width(5);
      m_ButtonBox.set_layout(Gtk::BUTTONBOX_END);
      m_Button_Quit.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_quit) );

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_quit()
    {
      hide();
    }

File: `main.cc`

    #include <gtkmm/main.h>
    #include "examplewindow.h"

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      Gtk::Main::run(window); //Shows the window and returns when it is closed.

      return 0;
    }

File: `treeview_withpopup.cc`

    #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
      Gtk::TreeModel::Row 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);

      //Fill popup menu:
      {
        Gtk::Menu::MenuList& menulist = m_Menu_Popup.items();

        menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Edit",
          sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic) ) );
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Process",
          sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic) ) );
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Remove",
          sigc::mem_fun(*this, &TreeView_WithPopup::on_menu_file_popup_generic) ) );
      }
      m_Menu_Popup.accelerate(*this);
    }

    TreeView_WithPopup::~TreeView_WithPopup()
    {
    }

    bool TreeView_WithPopup::on_button_press_event(GdkEventButton* event)
    {
      //Call base class, to allow normal handling,
      //such as allowing the row to be selected by the right-click:
      bool return_value = TreeView::on_button_press_event(event);

      //Then do our custom stuff:
      if( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) )
      {
        m_Menu_Popup.popup(event->button, event->time);
      }

      return return_value;
    }

    void TreeView_WithPopup::on_menu_file_popup_generic()
    {
      std::cout << "A popup menu item was selected." << std::endl;

      Glib::RefPtr<Gtk::TreeView::Selection> refSelection = get_selection();
      if(refSelection)
      {
        Gtk::TreeModel::iterator iter = refSelection->get_selected();
        if(iter)
        {
          int id = (*iter)[m_Columns.m_col_id];
          std::cout << "  Selected ID=" << id << std::endl;
        }
      }
    }

Popup Context Menu |  | Chapter 9. TextView