Re: custom TreeModel
- From: danny <danny van elsen skynet be>
- To: gtkmm-list gnome org
- Subject: Re: custom TreeModel
- Date: Mon, 16 Dec 2019 23:10:45 +0100
hi
well, actually, I did not find the example you are referring to. I probably did when I was working with the original gtk2 program, though.
so I have come up with this:
(gtkmm-3.22.3/demos)
--------------------------------------------------------------
/* Tree View/Tree Store
*
* The GtkTreeStore is used to store data in tree form, to be
* used later on by a GtkTreeView to display it. This demo builds
* a simple list of nodes in memory and displays it in the GtkTreeStore.
*
*/
#include <gtkmm.h>
//debug
#include <iostream>
#define MEMORY_TREEMODEL_COL_INT 0
#define MEMORY_TREEMODEL_COL_STRING 1
class Memory_Item
{
// one Memory Item will represent one chunk of information to
// be shown in the Treeview, i.e. one row with subnodes
public:
Memory_Item();
// data for top level nodes
int mi_1;
std::string mi_2;
// for first level of sub nodes
int mi_A1;
std::string mi_A2;
// for second level of sub nodes
int mi_B1;
std::string mi_B2;
};
Memory_Item::Memory_Item()
{
mi_1 = mi_A1 = mi_B1 = 0;
mi_2 = mi_A2 = mi_B2 = "";
}
class Memory
{
public:
Memory();
// these we will show in the treeview
std::vector <Memory_Item> v_mi;
};
Memory::Memory()
{
v_mi.clear();
}
class Memory_Columns: public Gtk::TreeModel::ColumnRecord
{
public:
Memory_Columns();
virtual ~Memory_Columns();
int Get_Columns_Count() const;
// a column for the ints
Gtk::TreeModelColumn<int> col_i;
// and a column for the strings
Gtk::TreeModelColumn<Glib::ustring> col_s;
private:
int n_columns;
};
Memory_Columns::Memory_Columns()
{
n_columns = 0;
add(col_i); n_columns++;
add(col_s); n_columns++;
}
Memory_Columns::~Memory_Columns()
{
}
int
Memory_Columns::Get_Columns_Count() const
{
return n_columns;
}
class Memory_TreeModel
: public Gtk::TreeModel , public Glib::Object
{
public:
Memory_TreeModel();
virtual ~Memory_TreeModel();
static Glib::RefPtr<Memory_TreeModel> create();
void Set_Memory(Memory *m);
// the gate for the model to the information to be shown
Memory *memory;
protected:
// Overrides:
virtual Gtk::TreeModelFlags get_flags_vfunc() const;
virtual int get_n_columns_vfunc() const;
virtual GType get_column_type_vfunc(int index) const;
virtual void get_value_vfunc(const TreeModel::iterator& iter, int column, Glib::ValueBase& value) const;
bool iter_next_vfunc(const iterator& iter, iterator& iter_next) const;
virtual bool iter_children_vfunc(const iterator& parent, iterator& iter) const;
virtual bool iter_has_child_vfunc(const iterator& iter) const;
virtual int iter_n_children_vfunc(const iterator& iter) const;
virtual int iter_n_root_children_vfunc() const;
virtual bool iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const;
virtual bool iter_nth_root_child_vfunc(int n, iterator& iter) const;
virtual bool iter_parent_vfunc(const iterator& child, iterator& iter) const;
virtual Path get_path_vfunc(const iterator& iter) const;
virtual bool get_iter_vfunc(const Path& path, iterator& iter) const;
private:
typedef Gtk::TreeModelColumn<Glib::ustring> StringColumn;
typedef Gtk::TreeModelColumn<int> IntColumn;
mutable IntColumn::ValueType ic;
mutable StringColumn::ValueType sc;
mutable StringColumn s_c;
mutable IntColumn i_c;
mutable int result_int;
mutable std::string result_string;
Memory_Columns m_columns;
};
Memory_TreeModel::Memory_TreeModel()
: Glib::ObjectBase( typeid(Memory_TreeModel) ),
Glib::Object()
{
Gtk::TreeModel::add_interface( Glib::Object::get_type() );
memory = 0;
sc.init( StringColumn::ValueType::value_type() );
ic.init( IntColumn::ValueType::value_type() );
}
Memory_TreeModel::~Memory_TreeModel()
{
}
Glib::RefPtr<Memory_TreeModel>
Memory_TreeModel::create()
{
return
Glib::RefPtr<Memory_TreeModel> (new Memory_TreeModel );
}
Gtk::TreeModelFlags
Memory_TreeModel::get_flags_vfunc() const
{
return Gtk::TreeModelFlags(0);
}
int
Memory_TreeModel::get_n_columns_vfunc() const
{
return m_columns.Get_Columns_Count();
}
void
Memory_TreeModel::get_value_vfunc(const TreeModel::iterator& iter, int column, Glib::ValueBase& value) const
{
// what information does one row contain?
Memory_Item mi;
unsigned long l;
unsigned long p; // path
//////////////////////////////////////////////////////////
// user_data contains the row number
l = (unsigned long) iter.gobj()->user_data;
if (l >= memory->v_mi.size())
{ return; }
// user_data2 contains the depth of the node
p = (unsigned long) iter.gobj()->user_data2;
mi = memory->v_mi.at(l);
switch (column)
{
case MEMORY_TREEMODEL_COL_INT:
{
if (p <= 1) // top level node
{result_int = mi.mi_1;}
else if (p == 2) // first sub node level
{result_int = mi.mi_A1;}
else // second sub node level
{result_int = mi.mi_B1;}
ic.set(result_int);
value.init( Glib::Value< int >::value_type() );
value = ic;
break;
}
case MEMORY_TREEMODEL_COL_STRING:
{
// same partitioning as for the ints
if (p <= 1) {result_string = mi.mi_2;}
else if (p == 2) {result_string = mi.mi_A2;}
else {result_string = mi.mi_B2;}
sc.set(result_string);
value.init( Glib::Value< std::string >::value_type() );
value = sc;
break;
}
}
}
bool
Memory_TreeModel::iter_next_vfunc(const iterator& iter, iterator& iter_next) const
{
// what is the next node from this one?
unsigned long l, p;
//////////////////////////////////////////////////////////
l = (unsigned long) iter.gobj()->user_data;
p = (unsigned long) iter.gobj()->user_data2;
if ( (l + 1 >= memory->v_mi.size()) // beyond the last row
|| (p > 1)) // the sublevels have just one child, no next node
{ iter_next = iterator(); return false; } //There is no next row.
l++; // next row
// set markers for next node
iter_next.gobj()->user_data = (void *) l;
iter_next.gobj()->user_data2 = (void *) p;
return true;
}
bool
Memory_TreeModel::iter_children_vfunc(const iterator& parent, iterator& iter) const
{
// get the first child of this parent node
return iter_nth_child_vfunc(parent, 0, iter);
}
bool
Memory_TreeModel::iter_has_child_vfunc(const iterator& iter) const
{
return (iter_n_children_vfunc(iter) > 0);
}
int
Memory_TreeModel::iter_n_children_vfunc(const iterator& iter) const
{
unsigned long l;
int n;
////////////////////////////////////////
l = (unsigned long) iter.gobj()->user_data2;
if (l == 0) // uninitiated node
{ n = 0;}
else if (l <= 2) // only two sublevels of nodes
{ n = 1;}
else
{ n = 0;} // no nodes
return n;
}
int
Memory_TreeModel::iter_n_root_children_vfunc() const
{
return memory->v_mi.size(); // number of rows
}
bool
Memory_TreeModel::iter_nth_child_vfunc(const iterator& parent, int n , iterator& iter) const
{
// get the nth child of this parent node
unsigned long l, p;
////////////////////////////////////////
p = (unsigned long) parent.gobj()->user_data;
l = (unsigned long) parent.gobj()->user_data2;
if ( (l > 2) // only two sublevels of nodes
|| (n > 0)) // and one child node only
{
iter = iterator();
return false; //There are no children.
}
iter.gobj()->user_data = (void*) p; // row index
iter.gobj()->user_data2 = (void*) (l + 1); // sublevel
return true;
}
bool
Memory_TreeModel::iter_nth_root_child_vfunc(int n, iterator& iter) const
{
// get the nth row
unsigned long l;
///////////////////////////////////////
l = n;
if (l >= memory->v_mi.size()) {return false; }
iter.gobj()->user_data = (void*) l; // row index
iter.gobj()->user_data2 = (void*) 1; // top level node
return true; // n <= available rows
}
bool
Memory_TreeModel::iter_parent_vfunc(const iterator& child, iterator& iter) const
{
// set a parent for this child
unsigned long l, p;
////////////////////////////////////////
l = (unsigned long) child.gobj()->user_data2;
p = (unsigned long) child.gobj()->user_data;
if (l <= 1) // top level
{
iter = iterator();
return false; //There are no children.
}
iter.gobj()->user_data = (void*) p; // row index
iter.gobj()->user_data2 = (void*) (l - 1); // one level up
return true;
}
bool
Memory_TreeModel::get_iter_vfunc(const Path& path, iterator& iter) const
{
// define a node
unsigned long ps; // path_size
unsigned long ri; // row_index
/////////////////////////////////////////////
ps = path.size();
if ( (!ps)
|| (ps > 3)) // only two levels of subnodes
{ iter = iterator(); return false; }
iter = iterator(); //clear the input parameter.
ri = path[0];
if (ri >= memory->v_mi.size())
{ iter = iterator(); return false; }
iter.gobj()->user_data = (void*) ri; // row index
iter.gobj()->user_data2 = (void*) ps; // sublevel
iter.gobj()->user_data3 = (void*) -1; // just to show its presence, really
return true;
}
Gtk::TreeModel::Path
Memory_TreeModel::get_path_vfunc(const iterator& /* iter */) const
{
//TODO:
return Path();
}
GType
Memory_TreeModel::get_column_type_vfunc(int index) const
{
switch (index)
{
case MEMORY_TREEMODEL_COL_INT:
{
return i_c.type();
break;
}
case MEMORY_TREEMODEL_COL_STRING:
{
return s_c.type();
break;
}
default:
{
return 0;
break;
}
}
}
class Example_TreeView_Memory : public Gtk::Window
{
public:
Example_TreeView_Memory();
~Example_TreeView_Memory() override;
protected:
//vfunc overrides:
void on_realize() override;
void fill_memory();
//Member widgets:
Gtk::Box m_VBox;
Gtk::ScrolledWindow m_ScrolledWindow;
Gtk::Label m_Label;
Memory_Columns memcol;
Glib::RefPtr<Memory_TreeModel> treemodel;
Gtk::TreeView treeview;
Memory mem_ory;
};
//Called by DemoWindow;
Gtk::Window* do_treeview_memory()
{
return new Example_TreeView_Memory();
}
Example_TreeView_Memory::Example_TreeView_Memory()
: m_VBox(Gtk::ORIENTATION_VERTICAL, 8),
m_Label("Analysis Sheet")
{
set_title("Memory analysis");
set_border_width(8);
set_default_size(650, 400);
add(m_VBox);
m_VBox.pack_start(m_Label, Gtk::PACK_SHRINK);
m_ScrolledWindow.set_shadow_type(Gtk::SHADOW_ETCHED_IN);
m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
m_VBox.pack_start(m_ScrolledWindow);
/* fill memory */
fill_memory();
/* create model */
treemodel = Memory_TreeModel::create();
treemodel->memory = &mem_ory;
/* treeview */
treeview.append_column("Integer", memcol.col_i);
treeview.append_column("String", memcol.col_s);
treeview.set_model(treemodel);
Glib::RefPtr<Gtk::TreeSelection> refTreeSelection = treeview.get_selection();
refTreeSelection->set_mode(Gtk::SELECTION_MULTIPLE);
m_ScrolledWindow.add(treeview);
show_all();
}
Example_TreeView_Memory::~Example_TreeView_Memory()
{
}
void Example_TreeView_Memory::fill_memory()
{
Memory_Item mi;
mi.mi_1 = 1; mi.mi_2 = "item 1"; mi.mi_A1 = 11; mi.mi_A2 = "item A11"; mi.mi_B1 = 111; mi.mi_B2 = "item B111";
mem_ory.v_mi.push_back(mi);
mi.mi_1 = 2; mi.mi_2 = "item 2"; mi.mi_A1 = 22; mi.mi_A2 = "item A22"; mi.mi_B1 = 222; mi.mi_B2 = "item B222";
mem_ory.v_mi.push_back(mi);
mi.mi_1 = 3; mi.mi_2 = "item 3"; mi.mi_A1 = 33; mi.mi_A2 = "item A33"; mi.mi_B1 = 333; mi.mi_B2 = "item B333";
mem_ory.v_mi.push_back(mi);
mi.mi_1 = 4; mi.mi_2 = "item 4"; mi.mi_A1 = 44; mi.mi_A2 = "item A44"; mi.mi_B1 = 444; mi.mi_B2 = "item B444";
mem_ory.v_mi.push_back(mi);
}
void Example_TreeView_Memory::on_realize()
{
treeview.expand_all();
//call base class:
Window::on_realize();
}
--------------------------------------------------------------
adapt demo.h
Gtk::Window* do_treeview_editable_cells();
Gtk::Window* do_treeview_liststore();
Gtk::Window* do_treeview_treestore();
Gtk::Window* do_treeview_memory();
Demo child0[] =
{
{ "Editable Cells", "example_treeview_editable_cells.cc", sigc::ptr_fun(&do_treeview_editable_cells), nullptr },
{ "List Store", "example_treeview_liststore.cc", sigc::ptr_fun(&do_treeview_liststore), nullptr },
{ "Tree Store", "example_treeview_treestore.cc", sigc::ptr_fun(&do_treeview_treestore), nullptr },
{ "Memory Tree Store", "example_treeview_memory.cc", sigc::ptr_fun(&do_treeview_memory), nullptr },
{ nullptr, nullptr, type_slotDo(), nullptr }
};
--------------------------------------------------------------
I'm not sure, though, if I really understand the purpose of
virtual bool Gtk::TreeModel::iter_parent_vfunc |
( |
|
this function finds a parent for the given child, right? but why would that be needed, if a child can only be arrived at from a parent node in the first place?
regards, Danny.
--------------------------------------------------------------
-----Original Message-----
Date: Sat, 14 Dec 2019 11:23:37 +0100
Subject: Re: custom TreeModel
Your custom TreeModel can perhaps be added either to the gtkmm
demo programs or to the gtkmm tutorial at
https://gitlab.gnome.org/GNOME/gtkmm-documentation. Let's decide
when you have a working program.
Have you noticed that there is a custom TreeModel example at
https://gitlab.gnome.org/GNOME/gtkmm-documentation/tree/gtkmm-3-24/examples/others/treemodelcustom
? I don't know if it's a good example. Most programs under the
examples/others directory are not maintained.
Kjell
On 2019-12-12 09:37, danny via
gtkmm-list wrote:
indeed! that seems to get me on my way! thanks!
if/when I get this working: would you be interested in adding
this to the gtkmm demo programs?
regards, D.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]