Examples
Prev | Chapter 8. The TreeView widget | Next

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

        Gtk::TreeModelColumn<unsigned 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::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::slot(*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_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";

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

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

      //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::slot(*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);

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

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

      //Tree model columns:
      class ModelColumns : public Gtk::TreeModel::ColumnRecord
      {
      public:

        ModelColumns()
        { add(m_col_id); add(m_col_name); add(m_col_foo); }

        Gtk::TreeModelColumn<unsigned int> m_col_id;
        Gtk::TreeModelColumn<Glib::ustring> m_col_name;
        Gtk::TreeModelColumn<bool> m_col_foo;
      };

      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 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::slot(*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_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_refTreeModel->append());
      row[m_Columns.m_col_id] = 3;
      row[m_Columns.m_col_name] = "Rob McRoberts";
      row[m_Columns.m_col_foo] = false;

      //Add the TreeView's view columns:
    #ifdef GTKMM_MSC_NET //MSVC++ can not cope with the easy method.
      {
         int cols_count = m_TreeView.append_column("ID", m_Columns.m_col_id);
         Gtk::TreeViewColumn* pColumn = m_TreeView.get_column(cols_count-1);
         Gtk::CellRendererText* pCell = dynamic_cast<Gtk::CellRendererText*>(pColumn->get_first_cell_renderer());
         pCell->property_editable() = true;
      }
      {
         int cols_count = m_TreeView.append_column("Name", m_Columns.m_col_name);
         Gtk::TreeViewColumn* pColumn = m_TreeView.get_column(cols_count-1);
         Gtk::CellRendererText* pCell = dynamic_cast<Gtk::CellRendererText*>(pColumn->get_first_cell_renderer());
         pCell->property_editable() = true;
      }

    #else //GTKMM_MSC_NET
      m_TreeView.append_column_editable("ID", m_Columns.m_col_id);
      m_TreeView.append_column_editable("Name", m_Columns.m_col_name);
    #endif //GTKMM_MSC_NET
      m_TreeView.append_column_editable("foo", m_Columns.m_col_foo);

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

### 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:
      explicit TreeModel_Dnd(const Gtk::TreeModelColumnRecord& columns);

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

      static ModelColumns m_Columns;

      static Glib::RefPtr<TreeModel_Dnd> create();

    protected:
      //Overridden virtual functions:
      virtual bool row_draggable_vfunc(const Gtk::TreeModel::Path& path);
      virtual bool row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, GtkSelectionData* selection_data);

    };

    #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::slot(*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>

    //Initialize static data:
    TreeModel_Dnd::ModelColumns TreeModel_Dnd::m_Columns;

    TreeModel_Dnd::TreeModel_Dnd(const Gtk::TreeModelColumnRecord& columns)
    : Gtk::TreeStore(columns)
    {
    }

    Glib::RefPtr<TreeModel_Dnd> TreeModel_Dnd::create()
    {
      return Glib::RefPtr<TreeModel_Dnd>( new TreeModel_Dnd(m_Columns) );
    }

    bool TreeModel_Dnd::row_draggable_vfunc(const Gtk::TreeModel::Path& path)
    {
      //Make the value of the "draggable" column determine whether this row can be dragged:

      const_iterator iter = get_iter(path);
      if(iter)
      {
        Row 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, GtkSelectionData* selection_data)
    {
      //Make the value of the "receives drags" column determine whether a row can be dragged into it:

      //dest is the path of the row after which the dragged path would be dropped.
      //But in this case we are more interested in the parent row:
      const_iterator iter = get_iter(dest);
      if(iter)
      {
        const_iterator iter_parent = iter->parent();
        if(iter_parent)
        {
          Row row = *iter_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.
      //TODO: Demonstrate this when the API has been corrected to use Gtk::SelectionData instead of GtkSelectionData,
      //and use Gtk::TreePath::get_from_selection_data(selection_data, model, path)

      return Gtk::TreeStore::row_drop_possible_vfunc(dest, selection_data);
    }

Prev | Up | Next
Drag and Drop | Home | Chapter 9. TextView