Usare il Gtk::TreeView con Glade

Autore: Fabio Di Matteo
Ultima revisione: 20/02/2018 - 12:05

E' possibile risparmiare tempo e tante righe di codice “disegnando” il treeview, il list store e l'intera grafica della nostra gui con l'editor di interfaccie Glade. Di seguito il codice commentato.

gui.ui

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="myListstore">
    <columns>
      <!-- column-name ID -->
      <column type="gint"/>
      <!-- column-name Nome -->
      <column type="gchararray"/>
      <!-- column-name Gradimento -->
      <column type="gint"/>
    </columns>
    <data>
      <row>
        <col id="0">1</col>
        <col id="1" translatable="yes">Fabio Di Matteo</col>
        <col id="2">50</col>
      </row>
      <row>
        <col id="0">2</col>
        <col id="1" translatable="yes">Tizio Rossi</col>
        <col id="2">10</col>
      </row>
    </data>
  </object>
  <object class="GtkWindow" id="window1">
    <property name="width_request">406</property>
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="has_resize_grip">True</property>
    <signal name="delete-event" handler="on_mainWindow_delete_event()" swapped="no"/>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkEntry" id="entry">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow">
            <property name="width_request">500</property>
            <property name="height_request">415</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="shadow_type">in</property>
            <child>
              <object class="GtkTreeView" id="myTreeView">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">myListstore</property>
                <property name="reorderable">True</property>
                <property name="search_column">1</property>
                <property name="activate_on_single_click">True</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection" id="myTreeSel"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="colID">
                    <property name="title" translatable="yes">ID</property>
                    <child>
                      <object class="GtkCellRendererSpin"/>
                      <attributes>
                        <attribute name="text">0</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="colNome">
                    <property name="title" translatable="yes">Nome</property>
                    <child>
                      <object class="GtkCellRendererText"/>
                      <attributes>
                        <attribute name="text">1</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn" id="colGradimento">
                    <property name="title" translatable="yes">Gradimento</property>
                    <child>
                      <object class="GtkCellRendererProgress"/>
                      <attributes>
                        <attribute name="value">2</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
    <child type="titlebar">
      <object class="GtkHeaderBar">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="title">GtkTreeview e Glade</property>
        <property name="subtitle">Come usare il treeview con glade</property>
        <property name="show_close_button">True</property>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkButton" id="btAdd">
                <property name="label">gtk-add</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <property name="always_show_image">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="btDel">
                <property name="label">gtk-delete</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <property name="always_show_image">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="btSave">
                <property name="label">gtk-save</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <property name="always_show_image">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="btClear">
                <property name="label">gtk-clear</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <property name="always_show_image">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">3</property>
              </packing>
            </child>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

main.cpp

#include <gtkmm.h>
#include "mainwindow.hpp"
 
int main(int argc, char *argv[])
{
	auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
	mainWindow mainw;
	return app->run(*mainw.window1);
}

mainwindow.hpp

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
 
#include <gtkmm.h>
 
class mainWindow  
{
	public:
		Glib::RefPtr<Gtk::Builder> builder;
		Gtk::Window *window1;
		Gtk::TreeView *treeView;
		Glib::RefPtr<Gtk::ListStore> listStore;
		Gtk::Entry *entry;
		Gtk::Button *add, *del, *save, *clear;
 
		mainWindow();
 
	protected:	
		void on_add_clicked();
		void on_delete_clicked();
		void on_save_clicked();
		void on_selection_changed();
		void on_clear_clicked();
 
	private:
		/* add your private declarations */
};
 
#endif /* MAINWINDOW_HPP */

mainwindow.cpp

#include "mainwindow.hpp"
#include <iostream>
 
 
mainWindow::mainWindow()
{
	auto builder = Gtk::Builder::create();
 
	try
	{
		builder->add_from_resource("/app/res/gui.ui");
	}
	catch(const Glib::FileError& ex)
	{
		std::cerr << "FileError: " << ex.what() << std::endl;
	}
	catch(const Glib::MarkupError& ex)
	{
		std::cerr << "MarkupError: " << ex.what() << std::endl;
	}
	catch(const Gtk::BuilderError& ex)
	{
		std::cerr << "BuilderError: " << ex.what() << std::endl;
	}
 
	builder->get_widget("window1", window1);
	builder->get_widget("myTreeView",treeView);
	listStore = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(builder->get_object("myListstore"));
 
	builder->get_widget("entry",entry);
	builder->get_widget("btAdd",add);
	builder->get_widget("btDel",del);
	builder->get_widget("btSave",save);
	builder->get_widget("btClear",clear);
 
 
	//Connetto i bottoni alle callbacks
	add->signal_clicked().connect(sigc::mem_fun(*this, &mainWindow::on_add_clicked) );
	del->signal_clicked().connect(sigc::mem_fun(*this, &mainWindow::on_delete_clicked) );
	save->signal_clicked().connect(sigc::mem_fun(*this, &mainWindow::on_save_clicked) );
	clear->signal_clicked().connect(sigc::mem_fun(*this, &mainWindow::on_clear_clicked) );
 
	//Connetto le callbacks per il Treeview (cambio di selezione riga)
	Glib::RefPtr<Gtk::TreeSelection> refTreeSelection =  treeView->get_selection();
	refTreeSelection->signal_changed().connect( sigc::mem_fun(*this,&mainWindow::on_selection_changed) );
 
}
 
//Aggiunge una riga al liststore
void mainWindow::on_add_clicked()
{
	static double gradimento=0;
	static int i ;
 
	i++;
	gradimento=gradimento+0.8;
 
	//La nostra classe personalizzata per specificare il modello di colonne:
  	class ModelColumns : public Gtk::TreeModel::ColumnRecord
  	{
  	public:
 
    		ModelColumns()
    		{ add(id); add(nome); add(gradimento); }
 
    		Gtk::TreeModelColumn<unsigned int> id;
    		Gtk::TreeModelColumn<Glib::ustring> nome;
			Gtk::TreeModelColumn<unsigned int> gradimento;
  	};
 
	ModelColumns m_Columns;
 
  	//Aggiungo le righe al liststore
  	Gtk::TreeModel::Row row = *(listStore->append());
  	row[m_Columns.id] = i;
  	row[m_Columns.nome] = entry->get_text();
  	row[m_Columns.gradimento] = gradimento;
}
 
void mainWindow::on_delete_clicked()
{
	Glib::RefPtr<Gtk::TreeSelection> refTreeSelection =  treeView->get_selection();
	Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
 
 
	if(iter) //se qualcosa è selezionato
	{
		listStore->Gtk::ListStore::erase(iter);
	}
}
 
void mainWindow::on_save_clicked()
{
	std::string nome;
	nome=entry->get_text();
 
	//Ricavo il valore di una riga selezionata
	Glib::RefPtr<Gtk::TreeSelection> refTreeSelection =  treeView->get_selection();
	Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
	if(iter) 
	{
	  //Prelevo il valore di una cella al click e lo salvo
	  Gtk::TreeModel::Row row = *iter;
	  row.set_value (1, nome );
	}
 
 
}
 
 
void mainWindow::on_selection_changed()
{
	std::string nome;
 
	//Ricavo il valore di una riga selezionata
	Glib::RefPtr<Gtk::TreeSelection> refTreeSelection =  treeView->get_selection();
	Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
	if(iter) 
	{
	  //Prelevo il valore di una cella al click e lo scrivo sulla entry
	  Gtk::TreeModel::Row row = *iter;
	  row.get_value (1, nome );
	  entry->set_text(nome);
	}
 
}
 
 
void mainWindow::on_clear_clicked()
{
	listStore->clear();
}