c++gtkmm

my custom column in a Gtk::TreeView doesn't work


I have a Gtk::TreeView, where I added a model and a custom column:

###examplewindow.hh:

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow
: public Gtk::Window
{
  public:
  ExampleWindow(void);
  virtual ~ExampleWindow(void);
  
  //My column
  class foocol
  : public Gtk::TreeView::Column
  {
    public:
    Gtk::CellRendererToggle fooRenderer;
    bool test;
    foocol(void);
    ~foocol(void);
    foocol(const foocol&);
    foocol &operator=(const foocol&);
    
    private:
    //signal
    void foocolData(Gtk::CellRenderer*,const Gtk::TreeModel::iterator&);
    void foocolToggled(const Glib::ustring&);
  };

  //Tree model columns:
  class ModelColumns : public Gtk::TreeModel::ColumnRecord
  {
    public:
    ModelColumns(void){ add(m_col_id); add(m_col_name); }

    Gtk::TreeModelColumn<unsigned int> m_col_id;
    Gtk::TreeModelColumn<Glib::ustring> m_col_name;
    Gtk::TreeModelColumn<ExampleWindow::foocol> m_col_foocol;
  };

  foocol m_foocol; // XXX
  ModelColumns m_Columns;

  //Child widgets:
  Gtk::TreeView m_TreeView;
  Glib::RefPtr<Gtk::ListStore> m_refTreeModel;
};

#endif //GTKMM_EXAMPLEWINDOW_H

###examplewindow.cc:

#include <iostream>
#include "examplewindow.hh"

#define CB_FUNCTION(X) sigc::mem_fun( this, &ExampleWindow::foocol::X )
#define CONNECT(X) connect( sigc::mem_fun( this,\
                                          &ExampleWindow::foocol::X ) );

ExampleWindow::ExampleWindow()
{
  set_title("List of singers");
  set_border_width(5);
  set_default_size(400, 200);

  //Add the TreeView, inside the window
  add(m_TreeView);

  //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] = "Marilyn Manson";


  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 2;
  row[m_Columns.m_col_name] = "David Vincent";


  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 3;
  row[m_Columns.m_col_name] = "Yolandi Visser";


  //Add the TreeView's view columns:
  //This number will be shown with the default numeric formatting.
  m_TreeView.append_column( "ID", m_Columns.m_col_id );
  m_TreeView.append_column( "Name", m_Columns.m_col_name );
  m_TreeView.append_column( "model.m_col_foocol", m_Columns.m_col_foocol );
  m_TreeView.append_column( m_foocol ); // XXX

  show_all_children();
  
}

ExampleWindow::~ExampleWindow()
{
  
}


ExampleWindow::foocol::foocol(  )
{ 
  std::cout << "foocol constructor " << this << "\n";
  this->set_title( "foocol" );
  this->pack_start( fooRenderer );
  
  //Tell the view column how to render the model values
  this->set_cell_data_func( fooRenderer, CB_FUNCTION( foocolData ) );
  
  
  fooRenderer.property_sensitive() = true; // done by default
  fooRenderer.signal_toggled().CONNECT( foocolToggled );
  
}

ExampleWindow::foocol::~foocol(  )
{
  std::cout << "foocol destructor " << this << "\n"; 
}

ExampleWindow::foocol::foocol( const ExampleWindow::foocol& copyMe )
: test(copyMe.test)
{ 
  std::cout << "foocol copy constructor " << this << "\n";
}

ExampleWindow::foocol&
ExampleWindow::foocol::operator=( const ExampleWindow::foocol& copyMe )
{
  std::cout << "assignement " << this << " = " << &copyMe << "\n";

  return *this;
}

                   /********* SIGNALS ******/
 
void
ExampleWindow::foocol::foocolData( Gtk::CellRenderer* renderer
                                 , const Gtk::TreeModel::iterator& 
                                                                  iter )
{
  std::cout << "foocolData " << this << "\n";
}

void
ExampleWindow::foocol::foocolToggled( const Glib::ustring& path )
{
  std::cout << "foocolToggled " << this << "\n";
}

###main.cc:

#include <iostream>
#include "examplewindow.hh"
#include <gtkmm/application.h>

int main( int argc
        , char *argv[] )
{
  Glib::RefPtr<Gtk::Application> app 
            = Gtk::Application::create( argc, argv
                                                , "org.gtkmm.example" );

  ExampleWindow window;

  //Shows the window and returns when it is closed.
  return app->run( window );
}

###compile on Linux:

g++ examplewindow.cc main.cc `pkg-config gtkmm-3.0 --cflags --libs` -std=c++11

###compile on Windows:

I'm not racist, I just don't know how to compile on Windows.

###screenshot: enter image description here

###the problem: ok, so as you can see I have spend some time to make a nice example of my problem. On the screenshot you can see one column named foocol where you can see a toggle, and just to the left, you can see a column named model.mcolfoocol.

The second column is where my problem is, I don't see the toggle at all. I don't know why, I spend hours failing to solve that issue...

Both column are identical, the different results come from one added as a column while the second (the one who doesn't work) is added through a Gtk::TreeModel::ColumnRecord . Of course I need to use the second method...

It may be better to comment lines where I added // XXX, so all messages in the console will be related to the problem.

###possible output:

foocol constructor 0xbfda6e70

(a.out:12545): Gtk-CRITICAL **: gtk_cell_layout_add_attribute: assertion 'column >= 0' failed
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocolData 0xbfda6e70
foocol destructor 0xbfda6e70

Unfortunately I don't know how to debug a program which uses several libs. I'm not even sure that my computer has enough memory to do that...


I really feel this part of gtkmm not intuitive...


Solution

  • You probably don't want to use ExampleWindow::foocal as a model-backing type (in Gtk::TreeModelColumn<ExampleWindow::foocol> m_col_foocol;); you are mixing TreeModel and TreeView types.

    I'm not sure of your intentions (why wouldn't you use just TreeModelColumn<bool>, which automatically renders a checkbox). Below I force your column to register with Model's ColumnRecord, and with View, and display (and generate toggle event, but not toggle correctly); note I needed to change it's type; hopefully this will help you to move in desired direction. I've commented out lines marked with // XXX, and also modified: