# [gtkmm] [C++] CheckButton in Gtk::ListView activatable?



## JKR (Jan 28, 2007)

Dear all,

I'm trying desperately to insert a CheckButton into a Gtk::ListView and use it.
So far, I can

- either use append_column_editable.

In this case, I can see my checkbox, I can click into it, but I cannot connect it to a signal handler, so clicking or unclicking the checkbox just changes the appearance but doesn't start any code.

- or use append_column and a cell renderer.

In this case, I can't click onto the checkbox at all, it just won't listen.

I thought this would be rather straightforward, but following the tutorial just doesn't seem enough to make even me understand :sigh:

So here is the code for someone more experienced than noobie me to have a look at. The errors are in line 89 (when uncommented, of course.)

Please feel free to comment on anything you'd change to make it better C++, as I'm trying to learn C++ at the moment.

Thanks a lot for your help and comments!




#include <gtkmm-2.4/gtkmm/treeview.h>

#include "Tree_View_Test.h"

/*
*
*/
Tree_View_Test::Tree_View_Test():

my_Box(false, 10),
my_Button_Test("Tree_View_Test_Button"),
my_Check_Button_Test("Tree_View_Test_CheckButton")


{
// Set title and border of the window
set_title("Tree View Test");
set_border_width(0);


add(my_Box);
my_Box.pack_start(my_Button_Test);
my_Box.pack_start(my_Check_Button_Test);

//add(my_Button_Test);
my_Button_Test.signal_clicked().connect(sigc::mem_fun(*this,
&Tree_View_Test:n_button_clicked) );
// my_Button_Test.show();

//add(my_Check_Button_Test);
my_Check_Button_Test.signal_clicked().connect(sigc::mem_fun(*this,
&Tree_View_Test:n_check_button_clicked) );

// my_Check_Button_Test.show();
my_Tree_View_Test_Tree_Model = Gtk::ListStore::create(my_Tree_View_Test_Columns);
my_Tree_View_Test_Tree_View.set_model(my_Tree_View_Test_Tree_Model);



Gtk::TreeModel::Row my_row;

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Button_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "New Record";

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Button_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "Fixed Text";


Gtk::CellRendererToggle* renderer = Gtk::manage( new Gtk::CellRendererToggle() );

// Gtk::CellRenderer* renderer = my_Tree_View_Test_Tree_View.get_column_cell_renderer(0);
// Gtk::CellRendererToggle* renderer = dynamic_cast<Gtk::CellRendererToggle*>(my_Tree_View_Test_Tree_View.get_column_cell_renderer(2) );

int cols_count = my_Tree_View_Test_Tree_View.append_column("myButtonInListView", *renderer);

// my_Tree_View_Test_Tree_View.append_column("myButtonInListView", my_Tree_View_Test_Columns.my_Button_In_List_View);
my_Tree_View_Test_Tree_View.append_column_editable("myCheckboxInListView", my_Tree_View_Test_Columns.my_Checkbox_In_List_View);
my_Tree_View_Test_Tree_View.append_column("myIdNumber", my_Tree_View_Test_Columns.my_Id_Number);
my_Tree_View_Test_Tree_View.append_column("myNameString", my_Tree_View_Test_Columns.my_Name_String);

Gtk::TreeViewColumn* pColumn = my_Tree_View_Test_Tree_View.get_column(cols_count-1);

if(pColumn)
{
pColumn->add_attribute(renderer->property_active(),
my_Tree_View_Test_Columns.my_Button_In_List_View);
pColumn->add_attribute(renderer->property_visible(),
my_Tree_View_Test_Columns.my_Button_In_List_View);
pColumn->add_attribute(renderer->property_activatable(),
my_Tree_View_Test_Columns.my_Button_In_List_View);

};

renderer->set_radio (false);
renderer->set_activatable (true);
renderer->set_active (true);
renderer->set_visible (true);


// renderer->signal_toggled().connect(
// sigc::bind( sigc::mem_fun(*this,
// &Tree_View_Test:n_checkbox_in_list_view_clicked), pColumn ));

my_Box.pack_start(my_Tree_View_Test_Tree_View);



std::cout << "And the renderer is - - " << renderer << "at adress " << &renderer << std::endl;

std::cout << "Renderer active?"
<< (renderer->get_active() ? "true" : "false")
<< std::endl;

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

my_Check_Button_Test.set_active(false);

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

my_Check_Button_Test.set_active(true);

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;



// my_Button_In_List_View.signal_clicked().connect(sigc::mem_fun(*this,
// &Tree_View_Test:n_check_button_in_list_view_clicked) );

// my_Checkbox_In_List_View.signal_clicked().connect(sigc::mem_fun(*this,
// &Tree_View_Test:n_checkbox_in_list_view_clicked) );


show_all_children();
}



Tree_View_Test::~Tree_View_Test()
{
}




void Tree_View_Test:n_button_clicked()
{
std::cout << "hey button clicked!" << std::endl;
}

void Tree_View_Test:n_check_button_clicked()
{
std::cout << "hey checkbutton was clicked!" << std::endl;
std::cout << "The Button was clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

}


const Glib::ustring& Tree_View_Test:n_check_button_in_list_view_clicked()
{
std::cout << "hey check_button in List_View was clicked!" << std::endl;
std::cout << "The Button was clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false") << std::endl;
(my_Check_Button_Test.get_active() ? my_Check_Button_Test.set_active(false) : my_Check_Button_Test.set_active(true) );

std::cout << "New state:" << (my_Check_Button_Test.get_active() ? "true" : "false") << std::endl;


}


const Glib::ustring& Tree_View_Test:n_checkbox_in_list_view_clicked()
{
std::cout << "hey check_button clicked!" << std::endl;
std::cout << "The Button was clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

// add here code to toggle the boolean value of the checkbox
(my_Check_Button_Test.get_active() ? my_Check_Button_Test.set_active(false) : my_Check_Button_Test.set_active(true) );

std::cout << "New state:" << (my_Check_Button_Test.get_active() ? "true" : "false") << std::endl;
}

And here is the corresponding .h file:

#ifndef _TREE_VIEW_TEST_H
#define	_TREE_VIEW_TEST_H


#include <iostream> //file handling
#include <fstream> //file handling
#include <cstdlib> //exit prototype

#include <gtkmm-2.4/gtkmm.h>
// #include <gtkmm-2.4/gtkmm/window.h>
// #include <gtkmm-2.4/gtkmm/box.h>
// #include <gtkmm-2.4/gtkmm/treeview.h>
// #include <gtkmm-2.4/gtkmm/treemodel.h>
// #include <gtkmm-2.4/gtkmm/liststore.h>
// #include <gtkmm-2.4/gtkmm/checkbutton.h>
// #include <gtkmm-2.4/gtkmm/button.h>
// #include <gtkmm-2.4/gtkmm/cellrenderer.h>
// #include <gtkmm-2.4/gtkmm/cellrenderertoggle.h>



class Tree_View_Test : public Gtk::Window
{
public:
Tree_View_Test();
virtual ~Tree_View_Test();
// Gtk::CellRenderer* ptrCellRenderer;
// Gtk::CellRendererToggle* cell;

Gtk::CellRendererToggle *renderer;
Gtk::CellRendererText *cell;
Gtk::TreeViewColumn* pColumn;
int cols_count;

protected:

//Signal handlers:

virtual void on_button_clicked();
virtual void on_check_button_clicked();
// virtual void on_check_button_in_list_view_clicked();
const Glib::ustring& on_check_button_in_list_view_clicked();
// virtual void on_checkbox_in_list_view_clicked();
const Glib::ustring& on_checkbox_in_list_view_clicked();




//Child widgets:

Gtk::VBox my_Box;
Gtk::Button my_Button_Test, my_Button_In_List_View;
Gtk::CheckButton my_Check_Button_Test, my_Checkbox_In_List_View;
Glib::RefPtr<Gtk::ListStore> my_Tree_View_Test_Tree_Model;
Gtk::TreeView my_Tree_View_Test_Tree_View;

GtkListStore *ListStore;
GtkTreeIter iter;



class Tree_View_Test_Columns : public Gtk::TreeModel::ColumnRecord
{
public:
Tree_View_Test_Columns()
{ add(my_Button_In_List_View); add(my_Checkbox_In_List_View); add(my_Id_Number); add(my_Name_String); }
Gtk::TreeModelColumn<bool> my_Button_In_List_View;
Gtk::TreeModelColumn<bool> my_Checkbox_In_List_View;
Gtk::TreeModelColumn<int> my_Id_Number;
Gtk::TreeModelColumn<Glib::ustring> my_Name_String;
};

Tree_View_Test_Columns my_Tree_View_Test_Columns;

};

#endif	/* _TREE_VIEW_TEST_H */


----------



## JKR (Jan 28, 2007)

I think I have an idea about why I can't hook up my signal that easily, but I still don't know how to implement it.

The problem seems to be that there are more than one checkbox in a column. So when I hook up the signal to the CellRendererToggle, it has to know somehow which checkbox generated the signal and has to either pass it on to the handler function or choose different handler functions corresponding to the different checkboxes.

The important part of the code is here:

Gtk::CellRendererToggle* renderer = Gtk::manage( new Gtk::CellRendererToggle() );

int cols_count = my_Tree_View_Test_Tree_View.append_column("myButtonInListView", *renderer);

Gtk::TreeViewColumn* pColumn = my_Tree_View_Test_Tree_View.get_column(cols_count-1);

And the problem is in

renderer->signal_toggled().connect(
sigc::bind( sigc::mem_fun(*this,
&Tree_View_Test:n_checkbox_in_list_view_clicked), pColumn ));


----------



## JKR (Jan 28, 2007)

Getting slowly better.  

It seems I've managed to get the hooker's syntax fairly right.
So now I can click into my checkboxes, the signal handler is called, and I can actually toggle the boolean value in my model. However, I did not yet find out how to make the renderer reflect this change: the checkboxes in my view don't get ticked or unticked, even though the underlying boolean value in the model is changed OK now. I can tick or untick all of the boxes in the columns using set_active on the renderer, but that's not really what I'd like to do....

So here is the revised code again (your comments / suggestions are much appreciated):

First, the .h file:

#ifndef _TREE_VIEW_TEST_H
#define _TREE_VIEW_TEST_H


#include <iostream> //file handling
#include <fstream> //file handling
#include <cstdlib> //exit prototype

#include <gtkmm-2.4/gtkmm.h>
// #include <gtkmm-2.4/gtkmm/window.h>
// #include <gtkmm-2.4/gtkmm/box.h>
// #include <gtkmm-2.4/gtkmm/treeview.h>
// #include <gtkmm-2.4/gtkmm/treemodel.h>
// #include <gtkmm-2.4/gtkmm/liststore.h>
// #include <gtkmm-2.4/gtkmm/checkbutton.h>
// #include <gtkmm-2.4/gtkmm/button.h>
// #include <gtkmm-2.4/gtkmm/cellrenderer.h>
// #include <gtkmm-2.4/gtkmm/cellrenderertoggle.h>



class Tree_View_Test : public Gtk::Window
{

public:

Tree_View_Test();
virtual ~Tree_View_Test();

Gtk::CellRendererToggle *renderer;
Gtk::CellRendererText *cell;
Gtk::TreeViewColumn* pColumn;
int cols_count;

protected:

//Signal handlers:

virtual void on_button_clicked();
virtual void on_check_button_clicked();
virtual void on_check_button_in_list_view_clicked();
virtual void on_checkbox_in_list_view_clicked(const Glib::ustring& path_string);


//Child widgets:

Gtk::VBox my_Box;
Gtk::Button my_Button_Test, my_Button_In_List_View;
Gtk::CheckButton my_Check_Button_Test, my_Checkbox_In_List_View;
Glib::RefPtr<Gtk::ListStore> my_Tree_View_Test_Tree_Model;
Gtk::TreeView my_Tree_View_Test_Tree_View;

GtkListStore *ListStore;
GtkTreeIter iter;



class Tree_View_Test_Columns : public Gtk::TreeModel::ColumnRecord
{
public:
Tree_View_Test_Columns()
{ add(my_Button_In_List_View); add(my_Checkbox_In_List_View); add(my_Id_Number); add(my_Name_String); }
Gtk::TreeModelColumn<bool> my_Button_In_List_View;
Gtk::TreeModelColumn<bool> my_Checkbox_In_List_View;
Gtk::TreeModelColumn<int> my_Id_Number;
Gtk::TreeModelColumn<Glib::ustring> my_Name_String;
};

Tree_View_Test_Columns my_Tree_View_Test_Columns;

};

#endif /* _TREE_VIEW_TEST_H */

And the cpp file:

#include <gtkmm-2.4/gtkmm/treeview.h>

#include "Tree_View_Test.h"

/*
*
*/
Tree_View_Test::Tree_View_Test():

my_Box(false, 10),
my_Button_Test("Tree_View_Test_Button"),
my_Check_Button_Test("Tree_View_Test_CheckButton")


{
// Set title and border of the window
set_title("Tree View Test");
set_border_width(0);


add(my_Box);
my_Box.pack_start(my_Button_Test);
my_Box.pack_start(my_Check_Button_Test);

//add(my_Button_Test);
my_Button_Test.signal_clicked().connect(sigc::mem_fun(*this,
&Tree_View_Test:n_button_clicked) );
// my_Button_Test.show();

//add(my_Check_Button_Test);
my_Check_Button_Test.signal_clicked().connect(sigc::mem_fun(*this,
&Tree_View_Test:n_check_button_clicked) );

// my_Check_Button_Test.show();
my_Tree_View_Test_Tree_Model = Gtk::ListStore::create(my_Tree_View_Test_Columns);
my_Tree_View_Test_Tree_View.set_model(my_Tree_View_Test_Tree_Model);



Gtk::TreeModel::Row my_row;

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Button_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "New Record";

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Button_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "Fixed Text";


Gtk::CellRendererToggle* renderer = Gtk::manage( dynamic_cast<Gtk::CellRendererToggle*> (new Gtk::CellRendererToggle() ));


int cols_count = my_Tree_View_Test_Tree_View.append_column("myButtonInListView", *renderer);

// my_Tree_View_Test_Tree_View.append_column("myButtonInListView", my_Tree_View_Test_Columns.my_Button_In_List_View);
my_Tree_View_Test_Tree_View.append_column_editable("myCheckboxInListView", my_Tree_View_Test_Columns.my_Checkbox_In_List_View);
my_Tree_View_Test_Tree_View.append_column("myIdNumber", my_Tree_View_Test_Columns.my_Id_Number);
my_Tree_View_Test_Tree_View.append_column("myNameString", my_Tree_View_Test_Columns.my_Name_String);

Gtk::TreeViewColumn* pColumn = my_Tree_View_Test_Tree_View.get_column(cols_count-1);


renderer->signal_toggled().connect(sigc::mem_fun(*this, &Tree_View_Test:n_checkbox_in_list_view_clicked));


/*
if(pColumn)
{
pColumn->add_attribute(renderer->property_active(),
my_Tree_View_Test_Columns.my_Button_In_List_View);
pColumn->add_attribute(renderer->property_visible(),
my_Tree_View_Test_Columns.my_Button_In_List_View);
pColumn->add_attribute(renderer->property_activatable(),
my_Tree_View_Test_Columns.my_Button_In_List_View);

};

*/

my_Box.pack_start(my_Tree_View_Test_Tree_View);



std::cout << "And the renderer is - - " << renderer << " at adress " << &renderer << std::endl;

std::cout << "Renderer active?"
<< (renderer->get_active() ? "true" : "false")
<< std::endl;

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

my_Check_Button_Test.set_active(false);

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

my_Check_Button_Test.set_active(true);

std::cout << "The Button was programmatically clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;


show_all_children();
}


Tree_View_Test::~Tree_View_Test()
{
}


void Tree_View_Test:n_button_clicked()
{
std::cout << "hey button clicked!" << std::endl;
}

void Tree_View_Test:n_check_button_clicked()
{
std::cout << "hey checkbutton was clicked!" << std::endl;
std::cout << "The Button was clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false")
<< std::endl;

}


void Tree_View_Test:n_check_button_in_list_view_clicked()
{
std::cout << "hey check_button in List_View was clicked!" << std::endl;
std::cout << "The Button was clicked: state="
<< (my_Check_Button_Test.get_active() ? "true" : "false") << std::endl;
(my_Check_Button_Test.get_active() ? my_Check_Button_Test.set_active(false) : my_Check_Button_Test.set_active(true) );

std::cout << "New state:" << (my_Check_Button_Test.get_active() ? "true" : "false") << std::endl;


}


void Tree_View_Test:n_checkbox_in_list_view_clicked(const Glib::ustring& path_string)
{

std::cout << "hey!!! check-box in List_View was clicked!" << std::endl;

std::cout << "The Button was clicked: state="
<< (my_Checkbox_In_List_View.get_active() ? "true" : "false")
<< std::endl;

// add here code to toggle the boolean value of the checkbox
(my_Checkbox_In_List_View.get_active() ? my_Checkbox_In_List_View.set_active(false) : my_Checkbox_In_List_View.set_active(true) );

std::cout << "New state:" << (my_Checkbox_In_List_View.get_active() ? "true" : "false") << std::endl;
}


----------



## JKR (Jan 28, 2007)

OK, so here is the solution I found, in case that it helps somebody else.
As I am a newbie to both C++ and gtkmm, please do not hesitate to comment on or improve this code. I might actually learn something!

#ifndef _TREE_VIEW_TEST_H
#define _TREE_VIEW_TEST_H

#include <iostream> //file handling
#include <fstream> //file handling
#include <cstdlib> //exit prototype

#include <gtkmm-2.4/gtkmm.h>

class Tree_View_Test : public Gtk::Window
{
public:

Tree_View_Test();
virtual ~Tree_View_Test();

protected:

//Signal handlers:

virtual void on_checkbox_in_list_view_clicked(const Glib::ustring& path_string);

//Child widgets:

Gtk::VBox my_Box;
Gtk::CheckButton my_Checkbox_In_List_View;
Glib::RefPtr<Gtk::ListStore> my_Tree_View_Test_Tree_Model;
Gtk::TreeView my_Tree_View_Test_Tree_View;
GtkListStore *ListStore;

Gtk::CellRendererToggle *renderer;
Gtk::TreeViewColumn* pColumn;
int cols_count;

class Tree_View_Test_Columns : public Gtk::TreeModel::ColumnRecord
{
public:
Tree_View_Test_Columns()
{ add(my_Checkbox_In_List_View);
add(my_Id_Number); add(my_Name_String);
}
Gtk::TreeModelColumn<bool> my_Checkbox_In_List_View;
Gtk::TreeModelColumn<int> my_Id_Number;
Gtk::TreeModelColumn<Glib::ustring> my_Name_String;
};

Tree_View_Test_Columns my_Tree_View_Test_Columns;

};

#endif /* _TREE_VIEW_TEST_H */



#include <gtkmm-2.4/gtkmm/treeview.h>

#include "Tree_View_Test.h"

Tree_View_Test::Tree_View_Test():

my_Box(false, 10)

{
set_title("Tree View Test");
set_border_width(0);

add(my_Box);

my_Tree_View_Test_Tree_Model = Gtk::ListStore::create(my_Tree_View_Test_Columns);
my_Tree_View_Test_Tree_View.set_model(my_Tree_View_Test_Tree_Model);

Gtk::TreeModel::Row my_row;

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "New Record";

my_row = *(my_Tree_View_Test_Tree_Model->append());
my_row[my_Tree_View_Test_Columns.my_Checkbox_In_List_View] = true;
my_row[my_Tree_View_Test_Columns.my_Id_Number] = 1;
my_row[my_Tree_View_Test_Columns.my_Name_String] = "Fixed Text";

Gtk::CellRendererToggle* renderer = Gtk::manage( dynamic_cast<Gtk::CellRendererToggle*> (new Gtk::CellRendererToggle() ));
renderer->signal_toggled().connect(sigc::mem_fun(*this, &Tree_View_Test:n_checkbox_in_list_view_clicked));

int cols_count = my_Tree_View_Test_Tree_View.append_column("myCheckboxInListView", *renderer);
my_Tree_View_Test_Tree_View.append_column("myIdNumber", my_Tree_View_Test_Columns.my_Id_Number);
my_Tree_View_Test_Tree_View.append_column("myNameString", my_Tree_View_Test_Columns.my_Name_String);

Gtk::TreeViewColumn* pColumn = my_Tree_View_Test_Tree_View.get_column(cols_count-1);

if(pColumn)
{
pColumn->add_attribute(renderer->property_active(),
my_Tree_View_Test_Columns.my_Checkbox_In_List_View);
}

my_Box.pack_start(my_Tree_View_Test_Tree_View);

show_all_children();
}


Tree_View_Test::~Tree_View_Test()
{
}


void Tree_View_Test:n_checkbox_in_list_view_clicked(const Glib::ustring& path_string)
{ 
Gtk::TreeModel::iterator iterat = my_Tree_View_Test_Tree_Model->get_iter(path_string);
Gtk::TreeModel::Row my_path_row = *iterat;

if(my_path_row.get_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View) == 1)
{
std::cout << my_path_row.get_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View) << std::endl;
my_path_row.set_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View, false);
std::cout << my_path_row.get_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View) << std::endl;
}

else
{
std::cout << my_path_row.get_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View) << std::endl;
my_path_row.set_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View, true);
std::cout << my_path_row.get_value(my_Tree_View_Test_Columns.my_Checkbox_In_List_View) << std::endl;
}
}


----------

