This example has a Gtk::TreeView widget, with a Gtk::ListStore model.
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;
}
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
#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;
}
This example is identical to the ListStore example, but it uses TreeView::append_column_editable() instead of TreeView::append_column().
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;
}
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
#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);
}