[gtkmm-documentation/gtkmm-3-24] Add examples/book/treeview/custom_treemodel
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtkmm-documentation/gtkmm-3-24] Add examples/book/treeview/custom_treemodel
- Date: Tue, 7 Jan 2020 13:50:57 +0000 (UTC)
commit 1aa9607a35b395a80c033e1002b3960eb9a3de3e
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date: Tue Jan 7 14:47:54 2020 +0100
Add examples/book/treeview/custom_treemodel
See https://mail.gnome.org/archives/gtkmm-list/2019-December/msg00014.html
Fixes #9 (Danny van Elsen)
docs/tutorial/C/index-in.docbook | 15 +-
examples/Makefile.am | 8 +
.../treeview/custom_treemodel/exampletreemodel.cc | 355 +++++++++++++++++++++
.../treeview/custom_treemodel/exampletreemodel.h | 133 ++++++++
.../treeview/custom_treemodel/examplewindow.cc | 107 +++++++
.../book/treeview/custom_treemodel/examplewindow.h | 54 ++++
examples/book/treeview/custom_treemodel/main.cc | 28 ++
examples/book/treeview/meson.build | 1 +
8 files changed, 696 insertions(+), 5 deletions(-)
---
diff --git a/docs/tutorial/C/index-in.docbook b/docs/tutorial/C/index-in.docbook
index f9e0f92..e036818 100644
--- a/docs/tutorial/C/index-in.docbook
+++ b/docs/tutorial/C/index-in.docbook
@@ -2898,13 +2898,22 @@ so that the right-click will cause the row to be selected first.
<sect1 id="sec-treeview-examples"><title>Examples</title>
+<para>Some <classname>TreeView</classname> examples are shown here. There are
+more examples in the <ulink url="&url_examples_base;treeview/">treeview directory</ulink>
+in <application>gtkmm-documentation</application>'s examples.</para>
+
+<para>If neither <classname>ListStore</classname> nor <classname>TreeStore</classname>
+is suitable for your application, look at the
+<ulink url="&url_examples_base;treeview/custom_treemodel">custom TreeModel</ulink>
+example. It shows how you can make your own implementation of the <classname>TreeModel</classname>
+interface.</para>
+
<sect2 id="liststore-example"><title>ListStore</title>
<para>
This example has a <classname>Gtk::TreeView</classname> widget, with a
<classname>Gtk::ListStore</classname> model.
</para>
-
<figure id="figure-treeview-liststore">
<title>TreeView - ListStore</title>
<screenshot>
@@ -2997,13 +3006,9 @@ section.
<para><ulink url="&url_examples_base;treeview/popup/">Source Code</ulink></para>
</sect2>
-
-
</sect1>
-
</chapter>
-
<chapter id="chapter-combobox">
<title>Combo Boxes</title>
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 8348bef..6ec1a5e 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -107,6 +107,7 @@ check_PROGRAMS = \
book/toolpalette/example \
book/tooltips/example \
book/treeview/combo_renderer/example \
+ book/treeview/custom_treemodel/example \
book/treeview/drag_and_drop/example \
book/treeview/editable_cells/example \
book/treeview/filter/example \
@@ -666,6 +667,13 @@ book_treeview_combo_renderer_example_SOURCES = \
book/treeview/combo_renderer/examplewindow.h \
book/treeview/combo_renderer/main.cc
+book_treeview_custom_treemodel_example_SOURCES = \
+ book/treeview/custom_treemodel/examplewindow.cc \
+ book/treeview/custom_treemodel/examplewindow.h \
+ book/treeview/custom_treemodel/main.cc \
+ book/treeview/custom_treemodel/exampletreemodel.cc \
+ book/treeview/custom_treemodel/exampletreemodel.h
+
book_treeview_drag_and_drop_example_SOURCES = \
book/treeview/drag_and_drop/examplewindow.cc \
book/treeview/drag_and_drop/examplewindow.h \
diff --git a/examples/book/treeview/custom_treemodel/exampletreemodel.cc
b/examples/book/treeview/custom_treemodel/exampletreemodel.cc
new file mode 100644
index 0000000..2490994
--- /dev/null
+++ b/examples/book/treeview/custom_treemodel/exampletreemodel.cc
@@ -0,0 +1,355 @@
+/* gtkmm example Copyright (C) 2020 gtkmm development team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "exampletreemodel.h"
+
+namespace
+{
+ enum
+ {
+ COL_INT,
+ COL_STRING
+ };
+}
+
+//////////////// MemoryItem
+
+MemoryItem::MemoryItem(int i)
+: mi_1(i), mi_2(Glib::ustring::format("item ", mi_1)),
+ mi_A1(11*i), mi_A2(Glib::ustring::format("item A", mi_A1)),
+ mi_B1(111*i), mi_B2(Glib::ustring::format("item B", mi_B1))
+{
+}
+
+//////////////// Memory
+
+void Memory::push_back(const MemoryItem& item)
+{
+ m_item.push_back(item);
+
+ if (m_model)
+ m_model->memory_row_inserted(m_item.size()-1);
+}
+
+void Memory::pop_back()
+{
+ if (m_item.size() > 0)
+ {
+ m_item.pop_back();
+
+ if (m_model)
+ m_model->memory_row_deleted(m_item.size());
+ }
+}
+
+void Memory::set_model(const Glib::RefPtr<MemoryTreeModel>& model)
+{
+ if (m_model)
+ m_model->set_memory(nullptr);
+
+ m_model = model;
+ if (m_model)
+ m_model->set_memory(this);
+}
+
+const MemoryItem& Memory::operator[](int i) const
+{
+ return m_item[i];
+}
+
+std::size_t Memory::size() const
+{
+ return m_item.size();
+}
+
+//////////////// MemoryColumn
+
+MemoryColumns::MemoryColumns()
+{
+ add(col_i);
+ add(col_s);
+}
+
+MemoryColumns::~MemoryColumns()
+{
+}
+
+//////////////// MemoryTreeModel
+
+MemoryTreeModel::MemoryTreeModel()
+: Glib::ObjectBase(typeid(MemoryTreeModel)), // Register a custom GType.
+ Glib::Object() // The custom GType is actually registered here.
+{
+ m_ic.init(IntColumn::ValueType::value_type());
+ m_sc.init(StringColumn::ValueType::value_type());
+}
+
+MemoryTreeModel::~MemoryTreeModel()
+{
+}
+
+Glib::RefPtr<MemoryTreeModel> MemoryTreeModel::create()
+{
+ return Glib::RefPtr<MemoryTreeModel>(new MemoryTreeModel);
+}
+
+void MemoryTreeModel::set_memory(const Memory* m)
+{
+ m_Memory = m;
+ ++m_stamp;
+}
+
+void MemoryTreeModel::memory_row_inserted(unsigned long i)
+{
+ if (!m_Memory)
+ return;
+
+ // Inform TreeView that a new node has been inserted, including two subnodes.
+ ++m_stamp;
+ iterator iter;
+ iter.set_stamp(m_stamp);
+ iter.gobj()->user_data = (void*)i; // row index
+ for (unsigned long depth = 1; depth <= 3; ++depth)
+ {
+ iter.gobj()->user_data2 = (void*)depth; // sublevel
+ row_inserted(get_path(iter), iter);
+ }
+}
+
+void MemoryTreeModel::memory_row_deleted(unsigned long i)
+{
+ if (!m_Memory)
+ return;
+
+ // Inform TreeView that a node has been deleted, including two subnodes.
+ ++m_stamp;
+ Path path(1, i);
+ for (unsigned long depth = 1; depth <= 3; ++depth)
+ {
+ row_deleted(path);
+ path.push_back(0); // Only one child node per level, index 0
+ }
+}
+
+Gtk::TreeModelFlags MemoryTreeModel::get_flags_vfunc() const
+{
+ return Gtk::TreeModelFlags(0);
+}
+
+int MemoryTreeModel::get_n_columns_vfunc() const
+{
+ return m_Columns.size();
+}
+
+// What information does one row contain?
+void MemoryTreeModel::get_value_vfunc(const iterator& iter, int column, Glib::ValueBase& value) const
+{
+ // user_data contains the row number
+ const unsigned long row = (unsigned long)iter.gobj()->user_data;
+
+ if (!is_valid(iter) || row >= m_Memory->size())
+ return;
+
+ // user_data2 contains the depth of the node
+ const unsigned long depth = (unsigned long)iter.gobj()->user_data2;
+
+ const MemoryItem& mi = (*m_Memory)[row];
+
+ switch (column)
+ {
+ case COL_INT:
+ {
+ int result_int = 0;
+ if (depth <= 1) // top level node
+ result_int = mi.mi_1;
+ else if (depth == 2) // first subnode level
+ result_int = mi.mi_A1;
+ else // second subnode level
+ result_int = mi.mi_B1;
+
+ m_ic.set(result_int);
+ value.init(m_ic.value_type());
+ value = m_ic;
+ break;
+ }
+ case COL_STRING:
+ {
+ Glib::ustring result_string;
+ // Same partitioning as for the ints
+ if (depth <= 1)
+ result_string = mi.mi_2;
+ else if (depth == 2)
+ result_string = mi.mi_A2;
+ else
+ result_string = mi.mi_B2;
+
+ m_sc.set(result_string);
+ value.init(m_sc.value_type());
+ value = m_sc;
+ break;
+ }
+ }
+}
+
+// What is the next node from this one?
+bool MemoryTreeModel::iter_next_vfunc(const iterator& iter, iterator& iter_next) const
+{
+ const unsigned long row = (unsigned long)iter.gobj()->user_data;
+ const unsigned long depth = (unsigned long)iter.gobj()->user_data2;
+
+ if (!is_valid(iter)
+ || row + 1 >= m_Memory->size() // beyond the last row
+ || depth > 1) // the sublevels have just one child, no next node
+ {
+ iter_next = iterator(); // There is no next row.
+ return false;
+ }
+
+ // Set markers for next node
+ iter_next.set_stamp(m_stamp);
+ iter_next.gobj()->user_data = (void*)(row + 1);
+ iter_next.gobj()->user_data2 = (void*)depth;
+ return true;
+}
+
+// Get the first child of this parent node
+bool MemoryTreeModel::iter_children_vfunc(const iterator& parent, iterator& iter) const
+{
+ return iter_nth_child_vfunc(parent, 0, iter);
+}
+
+bool MemoryTreeModel::iter_has_child_vfunc(const iterator& iter) const
+{
+ return iter_n_children_vfunc(iter) > 0;
+}
+
+int MemoryTreeModel::iter_n_children_vfunc(const iterator& iter) const
+{
+ const unsigned long depth = (unsigned long)iter.gobj()->user_data2;
+
+ if (!is_valid(iter) || depth == 0) // invalid or uninitialized node
+ return 0;
+ if (depth <= 2) // only two sublevels of nodes
+ return 1;
+ return 0; // no nodes
+}
+
+int MemoryTreeModel::iter_n_root_children_vfunc() const
+{
+ return m_Memory->size(); // number of rows
+}
+
+// Get the nth child of this parent node
+bool MemoryTreeModel::iter_nth_child_vfunc(const iterator& parent, int n , iterator& iter) const
+{
+ const unsigned long row = (unsigned long)parent.gobj()->user_data;
+ const unsigned long depth = (unsigned long)parent.gobj()->user_data2;
+
+ if (!is_valid(parent)
+ || depth > 2 // only two sublevels of nodes
+ || n > 0) // and one child node only
+ {
+ iter = iterator();
+ return false; // There are no children.
+ }
+
+ iter.set_stamp(m_stamp);
+ iter.gobj()->user_data = (void*)row; // row index
+ iter.gobj()->user_data2 = (void*)(depth + 1); // sublevel
+ return true;
+}
+
+// Get the nth row
+bool MemoryTreeModel::iter_nth_root_child_vfunc(int n, iterator& iter) const
+{
+ const unsigned long row = n;
+
+ if (row >= m_Memory->size())
+ {
+ iter = iterator();
+ return false; // No such row
+ }
+
+ iter.set_stamp(m_stamp);
+ iter.gobj()->user_data = (void*)row; // row index
+ iter.gobj()->user_data2 = (void*)1; // top level node
+ return true; // n < available rows
+}
+
+// Get the parent for this child
+bool MemoryTreeModel::iter_parent_vfunc(const iterator& child, iterator& iter) const
+{
+ const unsigned long row = (unsigned long)child.gobj()->user_data;
+ const unsigned long depth = (unsigned long)child.gobj()->user_data2;
+
+ if (!is_valid(child)
+ || depth <= 1) // top level
+ {
+ iter = iterator();
+ return false; // There is no parent.
+ }
+
+ iter.set_stamp(m_stamp);
+ iter.gobj()->user_data = (void*)row; // row index
+ iter.gobj()->user_data2 = (void*)(depth - 1); // one level up
+ return true;
+}
+
+// Define a node
+bool MemoryTreeModel::get_iter_vfunc(const Path& path, iterator& iter) const
+{
+ const unsigned long row = path[0]; // row_index
+ const unsigned long depth = path.size();
+
+ if (row >= m_Memory->size()
+ || depth == 0 || depth > 3) // only two levels of subnodes
+ {
+ iter = iterator();
+ return false;
+ }
+
+ iter.set_stamp(m_stamp);
+ iter.gobj()->user_data = (void*)row; // row index
+ iter.gobj()->user_data2 = (void*)depth; // sublevel
+ iter.gobj()->user_data3 = (void*)-1; // just to show its presence, really
+ return true;
+}
+
+Gtk::TreeModel::Path MemoryTreeModel::get_path_vfunc(const iterator& iter) const
+{
+ const unsigned long row = (unsigned long)iter.gobj()->user_data;
+ const unsigned long depth = (unsigned long)iter.gobj()->user_data2;
+
+ Path path(1, row);
+ for (unsigned long i = 2; i <= depth; ++i)
+ path.push_back(0); // Only one child node per level, index 0
+ return path;
+}
+
+GType MemoryTreeModel::get_column_type_vfunc(int index) const
+{
+ if (index < 0 || static_cast<unsigned int>(index) >= m_Columns.size())
+ return 0;
+
+ return m_Columns.types()[index];
+}
+
+bool MemoryTreeModel::is_valid(const iterator& iter) const
+{
+ // Anything that modifies the model's structure should change the model's stamp,
+ // so that old iterators are ignored.
+ return m_stamp == iter.get_stamp();
+}
diff --git a/examples/book/treeview/custom_treemodel/exampletreemodel.h
b/examples/book/treeview/custom_treemodel/exampletreemodel.h
new file mode 100644
index 0000000..d9c7631
--- /dev/null
+++ b/examples/book/treeview/custom_treemodel/exampletreemodel.h
@@ -0,0 +1,133 @@
+/* gtkmm example Copyright (C) 2020 gtkmm development team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GTKMM_EXAMPLETREEMODEL_H
+#define GTKMM_EXAMPLETREEMODEL_H
+
+#include <gtkmm.h>
+#include <vector>
+#include <utility>
+
+class MemoryTreeModel;
+
+// One MemoryItem will represent one chunk of information to
+// be shown in the Treeview, i.e. one row with subnodes.
+struct MemoryItem
+{
+ MemoryItem(int i);
+
+ // data for top level nodes
+ int mi_1 = 0;
+ Glib::ustring mi_2;
+
+ // for first level of subnodes
+ int mi_A1 = 0;
+ Glib::ustring mi_A2;
+
+ // for second level of subnodes
+ int mi_B1 = 0;
+ Glib::ustring mi_B2;
+};
+
+class Memory
+{
+public:
+ template <typename... Args>
+ void emplace_back(Args&&... args);
+
+ void push_back(const MemoryItem& item);
+ void pop_back();
+ void set_model(const Glib::RefPtr<MemoryTreeModel>& model);
+ const MemoryItem& operator[](int i) const;
+ std::size_t size() const;
+
+private:
+ // These we will show in the TreeView
+ std::vector<MemoryItem> m_item;
+
+ Glib::RefPtr<MemoryTreeModel> m_model;
+};
+
+class MemoryColumns: public Gtk::TreeModel::ColumnRecord
+{
+public:
+ MemoryColumns();
+ virtual ~MemoryColumns();
+
+ Gtk::TreeModelColumn<int> col_i; // A column for the ints
+ Gtk::TreeModelColumn<Glib::ustring> col_s; // A column for the strings
+};
+
+class MemoryTreeModel : public Gtk::TreeModel, public Glib::Object
+{
+public:
+ MemoryTreeModel();
+ virtual ~MemoryTreeModel();
+
+ static Glib::RefPtr<MemoryTreeModel> create();
+
+ void set_memory(const Memory* m = nullptr);
+ void memory_row_inserted(unsigned long i);
+ void memory_row_deleted(unsigned long i);
+
+protected:
+ // Overrides:
+ Gtk::TreeModelFlags get_flags_vfunc() const override;
+ int get_n_columns_vfunc() const override;
+ GType get_column_type_vfunc(int index) const override;
+ void get_value_vfunc(const iterator& iter, int column, Glib::ValueBase& value) const override;
+ bool iter_next_vfunc(const iterator& iter, iterator& iter_next) const override;
+ bool iter_children_vfunc(const iterator& parent, iterator& iter) const override;
+ bool iter_has_child_vfunc(const iterator& iter) const override;
+ int iter_n_children_vfunc(const iterator& iter) const override;
+ int iter_n_root_children_vfunc() const override;
+ bool iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const override;
+ bool iter_nth_root_child_vfunc(int n, iterator& iter) const override;
+ bool iter_parent_vfunc(const iterator& child, iterator& iter) const override;
+ Path get_path_vfunc(const iterator& iter) const override;
+ bool get_iter_vfunc(const Path& path, iterator& iter) const override;
+
+ // These vfuncs are optional to implement.
+ // void ref_node_vfunc(const iterator& iter) const override;
+ // void unref_node_vfunc(const iterator& iter) const override;
+
+ bool is_valid(const iterator& iter) const;
+
+private:
+ using IntColumn = Gtk::TreeModelColumn<int>;
+ using StringColumn = Gtk::TreeModelColumn<Glib::ustring>;
+
+ mutable IntColumn::ValueType m_ic;
+ mutable StringColumn::ValueType m_sc;
+
+ MemoryColumns m_Columns;
+
+ // The gate for the model to the information to be shown.
+ // The MemoryTreeModel does not own the data.
+ const Memory* m_Memory = nullptr;
+ // When the model's stamp and the TreeIter's stamp are equal, the TreeIter is valid.
+ int m_stamp = 0;
+};
+
+template <typename... Args>
+void Memory::emplace_back(Args&&... args)
+{
+ m_item.emplace_back(std::forward<Args>(args)...);
+ if (m_model)
+ m_model->memory_row_inserted(m_item.size()-1);
+}
+
+#endif // GTKMM_EXAMPLETREEMODEL_H
diff --git a/examples/book/treeview/custom_treemodel/examplewindow.cc
b/examples/book/treeview/custom_treemodel/examplewindow.cc
new file mode 100644
index 0000000..5962887
--- /dev/null
+++ b/examples/book/treeview/custom_treemodel/examplewindow.cc
@@ -0,0 +1,107 @@
+/* gtkmm example Copyright (C) 2020 gtkmm development team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <iostream>
+#include "examplewindow.h"
+
+ExampleWindow::ExampleWindow()
+: m_VBox(Gtk::ORIENTATION_VERTICAL, 8),
+ m_Label("Analysis Sheet"),
+ m_Button_Add("Add Node"),
+ m_Button_Remove("Remove Node"),
+ m_Button_Quit("Quit")
+{
+ set_title("Gtk::TreeView (custom TreeModel) example");
+ set_border_width(8);
+ set_default_size(650, 400);
+
+ add(m_VBox);
+ m_VBox.pack_start(m_Label, Gtk::PACK_SHRINK);
+
+ // 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_ScrolledWindow.set_shadow_type(Gtk::SHADOW_ETCHED_IN);
+
+ m_VBox.pack_start(m_ScrolledWindow);
+ m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);
+
+ m_ButtonBox.pack_start(m_Button_Add, Gtk::PACK_SHRINK);
+ m_ButtonBox.pack_start(m_Button_Remove, Gtk::PACK_SHRINK);
+ m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
+ m_ButtonBox.set_border_width(5);
+ m_ButtonBox.set_spacing(5);
+ m_ButtonBox.set_layout(Gtk::BUTTONBOX_END);
+ m_Button_Add.signal_clicked().connect(sigc::mem_fun(*this,
+ &ExampleWindow::on_button_add));
+ m_Button_Remove.signal_clicked().connect(sigc::mem_fun(*this,
+ &ExampleWindow::on_button_remove));
+ m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this,
+ &ExampleWindow::on_button_quit));
+
+ // Fill memory.
+ fill_memory(2);
+
+ // Create the Tree model:
+ m_refTreeModel = MemoryTreeModel::create();
+ m_Memory.set_model(m_refTreeModel);
+
+ // TreeView
+ m_TreeView.append_column("Integer", m_Columns.col_i);
+ m_TreeView.append_column("String", m_Columns.col_s);
+ m_TreeView.set_model(m_refTreeModel);
+
+ m_TreeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
+
+ show_all();
+}
+
+ExampleWindow::~ExampleWindow()
+{
+}
+
+void ExampleWindow::on_button_add()
+{
+ m_Memory.emplace_back(m_Memory.size()+1);
+ // Expand the appended row.
+ m_TreeView.expand_row(Gtk::TreeModel::Path(1, m_Memory.size()-1), true);
+}
+
+void ExampleWindow::on_button_remove()
+{
+ m_Memory.pop_back();
+}
+
+void ExampleWindow::on_button_quit()
+{
+ hide();
+}
+
+void ExampleWindow::fill_memory(int n_top_level_rows)
+{
+ for (int i = 1; i <= n_top_level_rows; ++i)
+ m_Memory.emplace_back(i);
+}
+
+void ExampleWindow::on_realize()
+{
+ m_TreeView.expand_all();
+
+ // Call base class:
+ Window::on_realize();
+}
diff --git a/examples/book/treeview/custom_treemodel/examplewindow.h
b/examples/book/treeview/custom_treemodel/examplewindow.h
new file mode 100644
index 0000000..66add22
--- /dev/null
+++ b/examples/book/treeview/custom_treemodel/examplewindow.h
@@ -0,0 +1,54 @@
+/* gtkmm example Copyright (C) 2020 gtkmm development team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GTKMM_EXAMPLEWINDOW_H
+#define GTKMM_EXAMPLEWINDOW_H
+
+#include <gtkmm.h>
+#include "exampletreemodel.h"
+
+class ExampleWindow : public Gtk::Window
+{
+public:
+ ExampleWindow();
+ virtual ~ExampleWindow();
+
+protected:
+ // Signal handlers:
+ void on_realize() override;
+ void on_button_add();
+ void on_button_remove();
+ void on_button_quit();
+
+ void fill_memory(int n_top_level_rows);
+
+ // Child widgets:
+ Gtk::Box m_VBox;
+ Gtk::ScrolledWindow m_ScrolledWindow;
+ Gtk::Label m_Label;
+ Gtk::TreeView m_TreeView;
+ Gtk::ButtonBox m_ButtonBox;
+ Gtk::Button m_Button_Add;
+ Gtk::Button m_Button_Remove;
+ Gtk::Button m_Button_Quit;
+
+ MemoryColumns m_Columns;
+ Glib::RefPtr<MemoryTreeModel> m_refTreeModel;
+
+ Memory m_Memory;
+};
+
+#endif // GTKMM_EXAMPLEWINDOW_H
diff --git a/examples/book/treeview/custom_treemodel/main.cc b/examples/book/treeview/custom_treemodel/main.cc
new file mode 100644
index 0000000..84aaccc
--- /dev/null
+++ b/examples/book/treeview/custom_treemodel/main.cc
@@ -0,0 +1,28 @@
+/* gtkmm example Copyright (C) 2020 gtkmm development team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "examplewindow.h"
+#include <gtkmm/application.h>
+
+int main(int argc, char* argv[])
+{
+ auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
+
+ ExampleWindow window;
+
+ // Shows the window and returns when it is closed.
+ return app->run(window);
+}
diff --git a/examples/book/treeview/meson.build b/examples/book/treeview/meson.build
index c154a96..3cc665d 100644
--- a/examples/book/treeview/meson.build
+++ b/examples/book/treeview/meson.build
@@ -9,6 +9,7 @@ exwindow_main = ['examplewindow.cc', 'main.cc']
examples_book_treeview = [
# [[dir-name], exe-name, [sources]]
[['combo_renderer'], 'example', exwindow_main],
+ [['custom_treemodel'], 'example', exwindow_main + ['exampletreemodel.cc']],
[['drag_and_drop'], 'example', exwindow_main + ['treemodel_dnd.cc']],
[['editable_cells'], 'example', exwindow_main],
[['filter'], 'example', exwindow_main],
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]