Re: custom TreeModel



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
Cc: gtkmm-list gnome org
To: danny <danny van elsen skynet be>
From: Kjell Ahlstedt <kjellahlstedt gmail com>

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]