Re: custom treemodel?



On 5/19/06, Murray Cumming <murrayc murrayc com> wrote:
>> > I don't have a lot of experience with GObject stuff, so I have no idea
>> > whether these should be necessary or not.  But it seems to run fine
>> > and doesn't issue a warning when those lines are commented out.  Any
>> > thoughts?
>>
>> Yes, I think I comment them out in Glom too.
>
> OK.  Then maybe I'll just get rid of them in the example.  Any objections?

No.

> So now the example runs without any warnings, and I've been working on
> ideas for a 'generic' custom treemodel.  I'm thinking about something
> like this:
>
> template <class T>

So T is a Standard C++ Container? Using
template <class T_Container> makes that a little clearer.

Yes, that's the idea.  Good point.

> class CustomTreeModel : public Gtk::TreeModel, public Glib::Object
> {
>   public:
>     Glib::RefPtr<CustomTreeModel> create(T container);
>     ...
>
>   protected:
>     CustomTreeModel(T container) :
>         Glib::ObjectBase(typeid(CustomTreeModel<T>)),
>         Glib::Object(),
>         m_container(container)
>     {}
>
>     // implement virtual functions
>     ...
>
>   private:
>     T m_container;
>     ...
> };

Yes, this is the ideal.

> Then an application developer would implement a specialization of
> this.  Something like:
>
> class MyListModel : public CustomTreeModel< std::list<MyAppType> >
> {
>   public:
>     typedef std::list<MyAppType> value_type;
>     Glib::RefPtr<MyListModel> create(value_type val);
>
>   protected:
>     MyListModel(value_type val) :
>         CustomTreeModel(val)
>     {}
>
>     // override any virtual methods for getting a value, number of
> columns, etc...
> };

Why would he need to derive a class? Wouldn't the templated class be enough?

Well, the CustomTreeModel class can implement a lot of the virtual
functions (i.e. iter_next_vfunc, things like that), but it can't very
easily implement anything related to values that are stored in the
container.  For example, say you want a custom treemodel that uses
std::vector<rgb_t> where rgb_t is defined as
struct rgb_t
{
int r, g, b
}

Do you want the model to have a single column of rgb_t objects, or do
you want three columns: an red column, a green column, and a blue
column?  Unless we want to limit the CustomTreeModel to only ever
having a single column, I think we need to rely on a more-derived
class to determine how the columns are defined (i.e. it needs to
implement get_n_columns_vfunc, etc.).  This certainly makes it more
complicated, but it also makes it more flexible.  But if you have any
ideas of how to do it all in one class, I'd certainly be happy to do
it that way.

> In fact i have a skeleton like this implemented to play around with,
> but I can't get it to instantiate.  When I call the
> MyListModel::create() function, I keep getting errors like this:
>
> glibmm-CRITICAL **: Glib::Interface::Interface(const
> Glib::Interface_Class&): assertion `gobject_ != 0' failed

Maybe you need to call the Glib::Object (or maybe ObjectBase, I forget)
constructor differently, if the example does that. Remember our discussion
about virtual inheritance.

Well, I call it exactly the same way as the example does it.  The main
difference is of course that I'm not actually instantiating that
class, but one derived from it.

Glib interfaces are implemented by GObjects. That's just how the GObject
type system works. So we need a GObject type, and each of our class
instances will need an instance of that GObject type.

Right.  Perhaps I just need to bite the bullet and brush up on some
GObject fundamentals.  gtkmm is very good about hiding most of the
GObject ugliness, but it seems like this is one instance where I may
need some additional background.

> Or should I be doing the GObject type registration in the most derived
> class (MyListModel) instead of CustomTreeModel?  Or is my approach
> just flawed in some basic way?

Yes, I suspect that you might need to call the Object constructor in the
most derived class. And that is where you are doing the type registration,
I  think.

OK, here are some results of some trial-and-error experimentation.
See if you can make sense of them :)

No Warnings:
===========
CustomTreeModel : public Gtk::TreeModel
MyListModel : public CustomTreeModel<>, virtual public Glib::Object
 - calls Object, ObjectBase constructor

CustomTreeModel : public Gtk::TreeModel, virtual public Glib::Object
 - calls Object, ObjectBase constructor
MyListModel : public CustomTreeModel<>, virtual public Glib::Object
 - calls Object, ObjectBase constructor

CustomTreeModel : public Gtk::TreeModel, virtual public Glib::Object
 - calls Object, ObjectBase constructor
MyListModel : public CustomTreeModel<>, virtual public Glib::Object

CustomTreeModel : public Gtk::TreeModel, virtual public Glib::Object
 - calls Object, ObjectBase constructor
MyListModel : public CustomTreeModel<>

Gives Warning:
============
CustomTreeModel : public Gtk::TreeModel, public Glib::Object
 - calls Object, ObjectBase constructor
MyListModel : public CustomTreeModel<>

CustomTreeModel : public Gtk::TreeModel
MyListModel : public CustomTreeModel<>, public Glib::Object
 - calls Object, ObjectBase constructor

Error, crash
============
CustomTreeModel : public Gtk::TreeModel, public Glib::Object
 - calls Object, ObjectBase constructor
MyListModel : public CustomTreeModel<>, public Glib::Object
 - calls Object, ObjectBase constructor


So it seems that when I use virtual inheritance, the warnings go away.
But I can't quite figure out why...  I haven't gotten around to
implementing enough of the class to see whether the model actually
works correctly, but the warnings are gone.  Now the question -- which
of the four non-warning choices is correct, if any?

Jonner



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]