Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Die Artikel ::  GTKmm Tutorial Teil 5     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
GPC
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 6310
Beitrag GPC Moderator 22:33:45 09.03.2008   Titel:   GTKmm Tutorial Teil 5            Zitieren

Grafische Benutzerschnittstellen in C++ mit gtkmm betriebssystemunabhängig gestalten Teil 5

In diesem Tutorial wird es um drei Komponenten gehen: Listen, Bäume und ComboBox-Felder. Auf den ersten Blick mögen sie nicht viel gemein haben, allerdings täuscht dieser hier, da sie alle auf der gleichen Technik basieren, die ich hier vorstellen möchte.

1 Das Gtk::TreeView

Das Gtk::TreeView wird zum Anzeigen von Listen und Baumstrukturen benutzt und ist eines der wichtigsten Widgets in einem Toolkit.

Ähnlich dem Verhältnis von Gtk::TextView und Gtk::TextBuffer gibt es auch hier mehrere Widgets, die involviert sind.

Eine gute Übersicht findet man unter [2].

Während das Gtk::TreeView nur die Darstellung von Informationen übernimmt, werden die Daten in einem Gtk::TreeModel abgelegt. Das Gtk::TreeModel-Widget stellt nur eine generische Schnittstelle dar und wird dann je nach Bedarf durch eine abgeleitete Klasse wie Gtk::ListStore oder Gtk::TreeStore ersetzt. Selbstverständlich kann man auch sein eigenes TreeModel erstellen, indem man von Gtk::TreeModel ableitet. In den allermeisten Fällen wird dies jedoch nicht nötig sein.

Außerdem wird ein Gtk::TreeView immer in ein Gtk::ScrolledWindow eingebettet, welches evilissimo in Teil 4 vorgestellt hat.

Grundsätzlich gilt es folgende Dinge zu tun, um das Gtk::TreeView zu benutzen:
  • Das Modell für die Spalten definieren
  • Gtk::TreeView erstellen
  • Gtk::TreeModel (bzw. eine seiner Subklassen) erstellen und an Gtk::TreeView zuweisen
  • Daten in das Gtk::TreeModel reinladen


1.1 Eine simple Liste

In diesem simplen Beispiel werden wir ein paar Daten in einer Liste darstellen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    public:
    Application() {
        set_title("ListStore Example");
        set_default_size(350,200);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        treeView.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 2485;
        row[cols.col_name] = "Staubsauger";
        row[cols.col_price] = 79.99f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2751;
        row[cols.col_name] = "Mixer";
        row[cols.col_price] = 25.75f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2982;
        row[cols.col_name] = "Waschmaschine";
        row[cols.col_price] = 699.99f;
        row[cols.col_stock] = false;

        //Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
        treeView.append_column("Produktnr.", cols.col_id);
        treeView.append_column("Name", cols.col_name);

        //Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
        treeView.append_column_numeric("Preis (EUR)", cols.col_price, "%.2f");

        //Die CheckBoxen werden automatisch gesetzt
        treeView.append_column("Am Lager", cols.col_stock);

        //Wir weisen das TreeView dem ScrollWindow zu
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <gtkmm.h>

class Application : public Gtk::Window {
//Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
class Columns : public Gtk::TreeModel::ColumnRecord {
public:
Columns() {
add(col_id);
add(col_name);
add(col_price);
add(col_stock);
}

~Columns() {}

Gtk::TreeModelColumn<unsigned> col_id;
Gtk::TreeModelColumn<Glib::ustring> col_name;
Gtk::TreeModelColumn<float> col_price;
Gtk::TreeModelColumn<bool> col_stock;
};

Gtk::VBox topBox;

//Hier die drei wichtigsten Komponenten
Gtk::ScrolledWindow scrollWindow;
Gtk::TreeView treeView;
Glib::RefPtr<Gtk::ListStore> listStore;

Columns cols;

public:
Application() {
set_title("ListStore Example");
set_default_size(350,200);

//Wir erstellen das ListStore und weisen es dem TreeView zu
treeView.set_model(listStore = Gtk::ListStore::create(cols));

//Wir fuegen noch ein paar Daten ein
Gtk::TreeModel::Row row = *(listStore->append());
row[cols.col_id] = 2485;
row[cols.col_name] = "Staubsauger";
row[cols.col_price] = 79.99f;
row[cols.col_stock] = true;

row = *(listStore->append());
row[cols.col_id] = 2751;
row[cols.col_name] = "Mixer";
row[cols.col_price] = 25.75f;
row[cols.col_stock] = true;

row = *(listStore->append());
row[cols.col_id] = 2982;
row[cols.col_name] = "Waschmaschine";
row[cols.col_price] = 699.99f;
row[cols.col_stock] = false;

//Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
treeView.append_column("Produktnr.", cols.col_id);
treeView.append_column("Name", cols.col_name);

//Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
treeView.append_column_numeric("Preis (EUR)", cols.col_price, "%.2f");

//Die CheckBoxen werden automatisch gesetzt
treeView.append_column("Am Lager", cols.col_stock);

//Wir weisen das TreeView dem ScrollWindow zu
scrollWindow.add(treeView);
scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

topBox.pack_start(scrollWindow);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    public:
    Application() {
        set_title("ListStore Example");
        set_default_size(350,200);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        treeView.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 2485;
        row[cols.col_name] = "Staubsauger";
        row[cols.col_price] = 79.99f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2751;
        row[cols.col_name] = "Mixer";
        row[cols.col_price] = 25.75f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2982;
        row[cols.col_name] = "Waschmaschine";
        row[cols.col_price] = 699.99f;
        row[cols.col_stock] = false;

        //Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
        treeView.append_column("Produktnr.", cols.col_id);
        treeView.append_column("Name", cols.col_name);

        //Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
        treeView.append_column_numeric("Preis (EUR)", cols.col_price, "%.2f");

        //Die CheckBoxen werden automatisch gesetzt
        treeView.append_column("Am Lager", cols.col_stock);

        //Wir weisen das TreeView dem ScrollWindow zu
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}


So sieht das dann aus:


Erwähnenswert ist, dass natürlich nur die Spalten angezeigt werden, die man per Gtk::TreeView::append_column-Methode hinzugefügt hat. Auf diese Art und Weise kann man leicht Daten "verstecken", indem man im ColumnModel weitere Eigenschaften deklariert, diese Spalten aber nicht hinzufügt. Später kann man die Spalte bei Bedarf mit einem Aufruf von Gtk::TreeView::append_column zur Laufzeit hinzufügen und mit Gtk::TreeView::remove_column auch wieder entfernen, wenn sie doch überflüssig wird.

1.2 Eine Baumstruktur

Nun ist so eine Liste mit Produkten ja etwas schönes, aber noch schöner wäre es, wenn wir unsere Produkte in Produktkategorien ablegen könnten. Hierzu werden wir nun eine Baumstruktur erstellen (der vorherige Quellcode ist Grundlage hierfür):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;
    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;

    //Nun brauchen wir ein TreeStore anstelle eines ListStores
    Glib::RefPtr<Gtk::TreeStore> treeStore;

    Columns cols;

    public:
    Application() {
        set_title("TreeStore Example");
        set_default_size(350,250);

        //Wir erstellen das TreeStore und weisen es dem TreeView zu
        treeView.set_model(treeStore = Gtk::TreeStore::create(cols));

        //Ein Knoten auf der ersten Ebene
        Gtk::TreeModel::Row row = *(treeStore->append());
        row[cols.col_id] = 2000;
        row[cols.col_name] = "Elektrogeräte";
        row[cols.col_price] = 0.0f;
        row[cols.col_stock] = false;

        //Drei Subknoten
        Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2485;
        childrow[cols.col_name] = "Staubsauger";
        childrow[cols.col_price] = 79.99f;
        childrow[cols.col_stock] = true;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2751;
        childrow[cols.col_name] = "Mixer";
        childrow[cols.col_price] = 25.75f;
        childrow[cols.col_stock] = true;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Waschmaschine";
        childrow[cols.col_price] = 699.99f;
        childrow[cols.col_stock] = false;

        //Wieder ein Knoten auf Ebene 1
        row = *(treeStore->append());
        row[cols.col_id] = 3000;
        row[cols.col_name] = "Reinigungsmittel";
        row[cols.col_price] = 0.0f;
        row[cols.col_stock] = false;

        //Und drei Subknoten
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3149;
        childrow[cols.col_name] = "Brof";
        childrow[cols.col_price] = 5.99f;
        childrow[cols.col_stock] = false;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3587;
        childrow[cols.col_name] = "Kill it!";
        childrow[cols.col_price] = 8.99f;
        childrow[cols.col_stock] = true;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Uber-Cleaner";
        childrow[cols.col_price] = 15.25f;
        childrow[cols.col_stock] = true;

        //Nun moechten wir noch, dass man bestimmte Spalten editieren kann
        //In dem Fall bleibt nur die Produktnummer unveraenderlich, alles
        //andere kann veraendert werden       

        treeView.append_column("Produktnr.", cols.col_id);
        treeView.append_column_editable("Name", cols.col_name);

        //Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
        treeView.append_column_numeric_editable("Preis (€)", cols.col_price,
                                                "%.2f");

        //Die CheckBoxen werden automatisch gesetzt
        treeView.append_column_editable("Am Lager", cols.col_stock);

        //Wir weisen das TreeView dem ScrollWindow zu
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <gtkmm.h>

class Application : public Gtk::Window {
//Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
class Columns : public Gtk::TreeModel::ColumnRecord {
public:
Columns() {
add(col_id);
add(col_name);
add(col_price);
add(col_stock);
}

~Columns() {}

Gtk::TreeModelColumn<unsigned> col_id;
Gtk::TreeModelColumn<Glib::ustring> col_name;
Gtk::TreeModelColumn<float> col_price;
Gtk::TreeModelColumn<bool> col_stock;
};

Gtk::VBox topBox;
//Hier die drei wichtigsten Komponenten
Gtk::ScrolledWindow scrollWindow;
Gtk::TreeView treeView;

//Nun brauchen wir ein TreeStore anstelle eines ListStores
Glib::RefPtr<Gtk::TreeStore> treeStore;

Columns cols;

public:
Application() {
set_title("TreeStore Example");
set_default_size(350,250);

//Wir erstellen das TreeStore und weisen es dem TreeView zu
treeView.set_model(treeStore = Gtk::TreeStore::create(cols));

//Ein Knoten auf der ersten Ebene
Gtk::TreeModel::Row row = *(treeStore->append());
row[cols.col_id] = 2000;
row[cols.col_name] = "Elektrogeräte";
row[cols.col_price] = 0.0f;
row[cols.col_stock] = false;

//Drei Subknoten
Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2485;
childrow[cols.col_name] = "Staubsauger";
childrow[cols.col_price] = 79.99f;
childrow[cols.col_stock] = true;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2751;
childrow[cols.col_name] = "Mixer";
childrow[cols.col_price] = 25.75f;
childrow[cols.col_stock] = true;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2982;
childrow[cols.col_name] = "Waschmaschine";
childrow[cols.col_price] = 699.99f;
childrow[cols.col_stock] = false;

//Wieder ein Knoten auf Ebene 1
row = *(treeStore->append());
row[cols.col_id] = 3000;
row[cols.col_name] = "Reinigungsmittel";
row[cols.col_price] = 0.0f;
row[cols.col_stock] = false;

//Und drei Subknoten
childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 3149;
childrow[cols.col_name] = "Brof";
childrow[cols.col_price] = 5.99f;
childrow[cols.col_stock] = false;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 3587;
childrow[cols.col_name] = "Kill it!";
childrow[cols.col_price] = 8.99f;
childrow[cols.col_stock] = true;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2982;
childrow[cols.col_name] = "Uber-Cleaner";
childrow[cols.col_price] = 15.25f;
childrow[cols.col_stock] = true;

//Nun moechten wir noch, dass man bestimmte Spalten editieren kann
//In dem Fall bleibt nur die Produktnummer unveraenderlich, alles
//andere kann veraendert werden

treeView.append_column("Produktnr.", cols.col_id);
treeView.append_column_editable("Name", cols.col_name);

//Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
treeView.append_column_numeric_editable("Preis (€)", cols.col_price,
"%.2f");

//Die CheckBoxen werden automatisch gesetzt
treeView.append_column_editable("Am Lager", cols.col_stock);

//Wir weisen das TreeView dem ScrollWindow zu
scrollWindow.add(treeView);
scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

topBox.pack_start(scrollWindow);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;
    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;

    //Nun brauchen wir ein TreeStore anstelle eines ListStores
    Glib::RefPtr<Gtk::TreeStore> treeStore;

    Columns cols;

    public:
    Application() {
        set_title("TreeStore Example");
        set_default_size(350,250);

        //Wir erstellen das TreeStore und weisen es dem TreeView zu
        treeView.set_model(treeStore = Gtk::TreeStore::create(cols));

        //Ein Knoten auf der ersten Ebene
        Gtk::TreeModel::Row row = *(treeStore->append());
        row[cols.col_id] = 2000;
        row[cols.col_name] = "Elektrogeräte";
        row[cols.col_price] = 0.0f;
        row[cols.col_stock] = false;

        //Drei Subknoten
        Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2485;
        childrow[cols.col_name] = "Staubsauger";
        childrow[cols.col_price] = 79.99f;
        childrow[cols.col_stock] = true;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2751;
        childrow[cols.col_name] = "Mixer";
        childrow[cols.col_price] = 25.75f;
        childrow[cols.col_stock] = true;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Waschmaschine";
        childrow[cols.col_price] = 699.99f;
        childrow[cols.col_stock] = false;

        //Wieder ein Knoten auf Ebene 1
        row = *(treeStore->append());
        row[cols.col_id] = 3000;
        row[cols.col_name] = "Reinigungsmittel";
        row[cols.col_price] = 0.0f;
        row[cols.col_stock] = false;

        //Und drei Subknoten
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3149;
        childrow[cols.col_name] = "Brof";
        childrow[cols.col_price] = 5.99f;
        childrow[cols.col_stock] = false;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3587;
        childrow[cols.col_name] = "Kill it!";
        childrow[cols.col_price] = 8.99f;
        childrow[cols.col_stock] = true;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Uber-Cleaner";
        childrow[cols.col_price] = 15.25f;
        childrow[cols.col_stock] = true;

        //Nun moechten wir noch, dass man bestimmte Spalten editieren kann
        //In dem Fall bleibt nur die Produktnummer unveraenderlich, alles
        //andere kann veraendert werden       

        treeView.append_column("Produktnr.", cols.col_id);
        treeView.append_column_editable("Name", cols.col_name);

        //Hier legen wir fest, wie die Spalte "Preis" formatiert werden soll
        treeView.append_column_numeric_editable("Preis (€)", cols.col_price,
                                                "%.2f");

        //Die CheckBoxen werden automatisch gesetzt
        treeView.append_column_editable("Am Lager", cols.col_stock);

        //Wir weisen das TreeView dem ScrollWindow zu
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}


Sieht doch schon ganz gut aus:


Hier ein Bild, bei dem ein Zweig geschlossen ist:


1.3 Auswahl und Zugriff auf Datensätze

In der Regel wird man mit den Daten, die ein Gtk::TreeView beinhaltet, etwas anstellen müssen. Meistens wird der User eine oder mehrere Zeilen auswählen und auf diese soll nun eine Aktion ausgeführt werden.

Generell gilt, dass auch das Gtk::TreeView mit Iteratoren arbeitet, um auf die Daten zuzugreifen. Hier heißt der Iterator Gtk::TreeModel::Iterator (dies ist ein typedef, im Original einfach Gtk::TreeIter).

Nun, um herauszufinden, was gerade ausgewählt ist, erstellt man zuerst ein Gtk::TreeView::Selection-Objekt:
C/C++ Code:
Glib::RefPtr<Gtk::TreeView::Selection> selection = treeView.get_selection();
C/C++ Code:
Glib::RefPtr<Gtk::TreeView::Selection> selection = treeView.get_selection();
C/C++ Code:
Glib::RefPtr<Gtk::TreeView::Selection> selection = treeView.get_selection();


Mit diesem Objekt können wir auch per set_mode(SelectionMode m) festlegen, ob Einfach- oder Mehrfachselektion verfügbar sein soll (Einfachauswahl ist die Voreinstellung). Abgesehen davon verwaltet dieses Objekt alles, was irgendwie mit der Auswahl zusammenhängt. So kann man per select(Gtk::TreeModel::Iterator) auch eine Auswahl setzen.

Nun, abhängig von Einfach- bzw. Mehrfachauswahl entscheiden wir über das weitere Vorgehen. Bei Einfachauswahl hat man es recht einfach:
C/C++ Code:
Gtk::TreeModel::iterator iter = selection->get_selected();
if(iter) {  //wurde eine Auswahl getroffen?
    Gtk::TreeModel::Row row = *iter;
   
    //Wir sind im Konkurrenzkampf, also wird der Preis halbiert
    row[cols.col_price] = row[cols.col_price] / 2;
}
C/C++ Code:
Gtk::TreeModel::iterator iter = selection->get_selected();
if(iter) { //wurde eine Auswahl getroffen?
Gtk::TreeModel::Row row = *iter;

//Wir sind im Konkurrenzkampf, also wird der Preis halbiert
row[cols.col_price] = row[cols.col_price] / 2;
}
C/C++ Code:
Gtk::TreeModel::iterator iter = selection->get_selected();
if(iter) {  //wurde eine Auswahl getroffen?
    Gtk::TreeModel::Row row = *iter;
   
    //Wir sind im Konkurrenzkampf, also wird der Preis halbiert
    row[cols.col_price] = row[cols.col_price] / 2;
}


Hat man jedoch Mehrfachauswahl eingestellt, wird die Geschichte ein wenig komplizierter, da man eine callback-Funktion erstellen muss:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
selection->selected_foreach_iter( sigc::mem_fun(*this, &Application::handle_multiple_selection) );

void Application::handle_multiple_selection(const Gtk::TreeModel::iterator &iter) {
    Gtk::TreeModel::Row row = *iter;
   
    //Wir sind immer noch im Konkurrenzkampf, also wird der Preis ueber die ganze Selektion halbiert ;-)
    row[cols.col_price] = row[cols.col_price] / 2;
}
C/C++ Code:
1
2
3
4
5
6
7
8
selection->selected_foreach_iter( sigc::mem_fun(*this, &Application::handle_multiple_selection) );

void Application::handle_multiple_selection(const Gtk::TreeModel::iterator &iter) {
Gtk::TreeModel::Row row = *iter;

//Wir sind immer noch im Konkurrenzkampf, also wird der Preis ueber die ganze Selektion halbiert ;-)
row[cols.col_price] = row[cols.col_price] / 2;
}
C/C++ Code:
1
2
3
4
5
6
7
8
selection->selected_foreach_iter( sigc::mem_fun(*this, &Application::handle_multiple_selection) );

void Application::handle_multiple_selection(const Gtk::TreeModel::iterator &iter) {
    Gtk::TreeModel::Row row = *iter;
   
    //Wir sind immer noch im Konkurrenzkampf, also wird der Preis ueber die ganze Selektion halbiert ;-)
    row[cols.col_price] = row[cols.col_price] / 2;
}


Dieser Code bewirkt, dass die Methode handle_multiple_selection für jedes Element der Auswahl aufgerufen und abgearbeitet wird.

Im Prinzip haben wir nun durch die "Preisveränderungen" auch schon gesehen, wie man auf die Daten zugreift. Der Weg ist immer der gleiche:
  • Selection-Objekt holen
  • Iterator auf Element(e) holen (egal ob per callback oder direkt)
  • Ein Gtk::TreeModel:Row erstellen
  • Daten lesen/ändern


1.4 Gtk::Cellrenderer

Bisher haben wir in unseren Listen/Bäumen immer nur Text, Zahlen oder auch mal eine CheckBox angezeigt. Nun bietet gtkmm über die Klasse Gtk::CellRenderer (und den Derivaten) diverse Möglichkeiten, Informationen darzustellen. Seien es nun Bilder, CheckBoxen, SpinButtons oder Fortschrittsanzeigen. Eine Übersicht findet man unter [3].

Ich möchte hier am Beispiel einer Liste zeigen, wie das geht.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_colour);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_colour;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    public:
        Application() {
        set_title("ListStore Example");
        set_default_size(200,200);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        treeView.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 0;
        row[cols.col_colour] = "red";

        row = *(listStore->append());
        row[cols.col_id] = 1;
        row[cols.col_colour] = "blue";

        row = *(listStore->append());
        row[cols.col_id] = 2;
        row[cols.col_colour] = "green";
       
        row = *(listStore->append());
        row[cols.col_id] = 3;
        row[cols.col_colour] = "white";
       
        treeView.append_column("Id", cols.col_id);

        //Die Spalte Colour soll farbig dargestellt werden
        //Zuerst legen wir einen entsprechenden CellRenderer an

        Gtk::CellRendererText *cell = new Gtk::CellRendererText;

        //Wir fuegen die Spalte hinzu
        int column_count = treeView.append_column("Colour", *cell);

        //Dann holen wir uns die gerade hinzugefuegte Spalte
        Gtk::TreeViewColumn *column = treeView.get_column(column_count-1);

        //Und sagen dann, woher die Informationen kommen und
        //wie sie dargestellt werden sollen

        if (column) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
            column->add_attribute(cell->property_text(), cols.col_colour);
            column->add_attribute(cell->property_background(), cols.col_colour);
#else

            column->add_attribute(*cell, "text", cols.col_colour);
            column->add_attribute(*cell, "background", cols.col_colour);
#endif

        }
       
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <gtkmm.h>

class Application : public Gtk::Window {
//Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
class Columns : public Gtk::TreeModel::ColumnRecord {
public:
Columns() {
add(col_id);
add(col_colour);
}

~Columns() {}

Gtk::TreeModelColumn<unsigned> col_id;
Gtk::TreeModelColumn<Glib::ustring> col_colour;
};

Gtk::VBox topBox;

//Hier die drei wichtigsten Komponenten
Gtk::ScrolledWindow scrollWindow;
Gtk::TreeView treeView;
Glib::RefPtr<Gtk::ListStore> listStore;

Columns cols;

public:
Application() {
set_title("ListStore Example");
set_default_size(200,200);

//Wir erstellen das ListStore und weisen es dem TreeView zu
treeView.set_model(listStore = Gtk::ListStore::create(cols));

//Wir fuegen noch ein paar Daten ein
Gtk::TreeModel::Row row = *(listStore->append());
row[cols.col_id] = 0;
row[cols.col_colour] = "red";

row = *(listStore->append());
row[cols.col_id] = 1;
row[cols.col_colour] = "blue";

row = *(listStore->append());
row[cols.col_id] = 2;
row[cols.col_colour] = "green";

row = *(listStore->append());
row[cols.col_id] = 3;
row[cols.col_colour] = "white";

treeView.append_column("Id", cols.col_id);

//Die Spalte Colour soll farbig dargestellt werden
//Zuerst legen wir einen entsprechenden CellRenderer an

Gtk::CellRendererText *cell = new Gtk::CellRendererText;

//Wir fuegen die Spalte hinzu
int column_count = treeView.append_column("Colour", *cell);

//Dann holen wir uns die gerade hinzugefuegte Spalte
Gtk::TreeViewColumn *column = treeView.get_column(column_count-1);

//Und sagen dann, woher die Informationen kommen und
//wie sie dargestellt werden sollen

if (column) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
column->add_attribute(cell->property_text(), cols.col_colour);
column->add_attribute(cell->property_background(), cols.col_colour);
#else

column->add_attribute(*cell, "text", cols.col_colour);
column->add_attribute(*cell, "background", cols.col_colour);
#endif

}

scrollWindow.add(treeView);
scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

topBox.pack_start(scrollWindow);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_colour);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_colour;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::TreeView treeView;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    public:
        Application() {
        set_title("ListStore Example");
        set_default_size(200,200);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        treeView.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 0;
        row[cols.col_colour] = "red";

        row = *(listStore->append());
        row[cols.col_id] = 1;
        row[cols.col_colour] = "blue";

        row = *(listStore->append());
        row[cols.col_id] = 2;
        row[cols.col_colour] = "green";
       
        row = *(listStore->append());
        row[cols.col_id] = 3;
        row[cols.col_colour] = "white";
       
        treeView.append_column("Id", cols.col_id);

        //Die Spalte Colour soll farbig dargestellt werden
        //Zuerst legen wir einen entsprechenden CellRenderer an

        Gtk::CellRendererText *cell = new Gtk::CellRendererText;

        //Wir fuegen die Spalte hinzu
        int column_count = treeView.append_column("Colour", *cell);

        //Dann holen wir uns die gerade hinzugefuegte Spalte
        Gtk::TreeViewColumn *column = treeView.get_column(column_count-1);

        //Und sagen dann, woher die Informationen kommen und
        //wie sie dargestellt werden sollen

        if (column) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
            column->add_attribute(cell->property_text(), cols.col_colour);
            column->add_attribute(cell->property_background(), cols.col_colour);
#else

            column->add_attribute(*cell, "text", cols.col_colour);
            column->add_attribute(*cell, "background", cols.col_colour);
#endif

        }
       
        scrollWindow.add(treeView);
        scrollWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
       
        topBox.pack_start(scrollWindow);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}


Ergebnis:


An sich hat sich unser Programm nicht groß verändert, nur das Hinzufügen der letzten Spalte ist neu. Natürlich hat jeder der verschiedenen Gtk::CellRenderer sein eigenes Property, welches man setzen muss, damit die Daten angezeigt werden. Jedoch greift einem die Dokumentation hier unter die Arme und sagt, welches Property gesetzt werden muss.

2 Die "Gtk::ComboBoxen"

gtkmm bietet vier ComboBoxen an: Gtk::ComboBox, Gtk::ComboBoxText, Gtk::ComboBoxEntry und Gtk::ComboBoxEntryText, wobei Gtk::ComboBox die Basisklasse und die anderen drei ComboBoxen Spezialisierungen darstellen. Für Gtk::ComboBox und Gtk::ComboBoxEntry muss man zuerst ein Gtk::TreeModel erstellen, bevor man Einträge hinzufügen kann (hier wird auch die Gemeinsamkeit mit Gtk::TreeView deutlich, auf die ich bereits einführend hingewiesen habe). Bei den anderen beiden hingegen benutzt man append_text um Einträge einzufügen.

Nun, schauen wir uns die einzelnen Komponenten an.

2.1 Gtk::ComboBox und Gtk::ComboBoxText

Die Vorgehensweise bei einer Gtk::ComboBox ist fast gleich wie bei einem Gtk::TreeView:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_market_share);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<int> col_market_share;
    };

    Gtk::VBox topBox;

    Gtk::ComboBox comboBox;
    Glib::RefPtr<Gtk::TreeStore> treeStore;

    Columns cols;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        Gtk::TreeModel::iterator iter = comboBox.get_active();
        if (iter) {
            Gtk::TreeModel::Row row = *iter;
            if (row) {
                std::cout    <<"ID: "<<row[cols.col_id]<<'\n'
                            <<"Name: "<<row[cols.col_name]<<'\n'
                            <<"Marktanteil: "<<row[cols.col_market_share]<<std::endl;
            }
        }
    }

    public:
    Application() {
        set_title("Gtk::ComboBox Example");
        set_default_size(300,25);

        //Wir erstellen das TreeStore und weisen es dem TreeView zu
        comboBox.set_model(treeStore = Gtk::TreeStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        //Ein Knoten auf der ersten Ebene

        Gtk::TreeModel::Row row = *(treeStore->append());
        row[cols.col_id] = 2000;
        row[cols.col_name] = "Elektrogeräte";
        row[cols.col_market_share] = 23;

        //Drei Subknoten
        Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2485;
        childrow[cols.col_name] = "Staubsauger";
        childrow[cols.col_market_share] = 40;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2751;
        childrow[cols.col_name] = "Mixer";
        childrow[cols.col_market_share] = 10;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Waschmaschine";
        childrow[cols.col_market_share] = 20;

        //Wieder ein Knoten auf Ebene 1
        row = *(treeStore->append());
        row[cols.col_id] = 3000;
        row[cols.col_name] = "Reinigungsmittel";
        row[cols.col_market_share] = 32;

        //Und drei Subknoten
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3149;
        childrow[cols.col_name] = "Brof";
        childrow[cols.col_market_share] = 12;
   
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3587;
        childrow[cols.col_name] = "Kill it!";
        childrow[cols.col_market_share] = 19;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Uber-Cleaner";
        childrow[cols.col_market_share] = 67;

        //Wir fuegen die Spalten hinzu
        comboBox.pack_start(cols.col_name);

        //Die Spalte Marktanteil soll als Fortschrittsbalken dargestellt werden
        //Zuerst legen wir einen entsprechenden CellRenderer an

        Gtk::CellRendererProgress *cell = new Gtk::CellRendererProgress;

        //Wir fuegen den CellRenderer bzw. die Spalte hinzu
        comboBox.pack_start(*cell);

        //Und sagen dann, woher die Informationen kommen, die dargestellt werden
        if (cell) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
            comboBox.add_attribute(cell->property_value(), cols.col_market_share);
#else

            comboBox.add_attribute(*cell, "value", cols.col_market_share);
#endif

        }

        //Erstes Element soll vorselektiert sein
        comboBox.set_active(0);
       
        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
//Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
class Columns : public Gtk::TreeModel::ColumnRecord {
public:
Columns() {
add(col_id);
add(col_name);
add(col_market_share);
}

~Columns() {}

Gtk::TreeModelColumn<unsigned> col_id;
Gtk::TreeModelColumn<Glib::ustring> col_name;
Gtk::TreeModelColumn<int> col_market_share;
};

Gtk::VBox topBox;

Gtk::ComboBox comboBox;
Glib::RefPtr<Gtk::TreeStore> treeStore;

Columns cols;

protected:
//Signalhandler der reagiert, sobald sich die Auswahl aendert
virtual void on_combo_changed() {
Gtk::TreeModel::iterator iter = comboBox.get_active();
if (iter) {
Gtk::TreeModel::Row row = *iter;
if (row) {
std::cout <<"ID: "<<row[cols.col_id]<<'\n'
<<"Name: "<<row[cols.col_name]<<'\n'
<<"Marktanteil: "<<row[cols.col_market_share]<<std::endl;
}
}
}

public:
Application() {
set_title("Gtk::ComboBox Example");
set_default_size(300,25);

//Wir erstellen das TreeStore und weisen es dem TreeView zu
comboBox.set_model(treeStore = Gtk::TreeStore::create(cols));

//Wir fuegen noch ein paar Daten ein
//Ein Knoten auf der ersten Ebene

Gtk::TreeModel::Row row = *(treeStore->append());
row[cols.col_id] = 2000;
row[cols.col_name] = "Elektrogeräte";
row[cols.col_market_share] = 23;

//Drei Subknoten
Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2485;
childrow[cols.col_name] = "Staubsauger";
childrow[cols.col_market_share] = 40;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2751;
childrow[cols.col_name] = "Mixer";
childrow[cols.col_market_share] = 10;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2982;
childrow[cols.col_name] = "Waschmaschine";
childrow[cols.col_market_share] = 20;

//Wieder ein Knoten auf Ebene 1
row = *(treeStore->append());
row[cols.col_id] = 3000;
row[cols.col_name] = "Reinigungsmittel";
row[cols.col_market_share] = 32;

//Und drei Subknoten
childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 3149;
childrow[cols.col_name] = "Brof";
childrow[cols.col_market_share] = 12;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 3587;
childrow[cols.col_name] = "Kill it!";
childrow[cols.col_market_share] = 19;

childrow = *(treeStore->append(row.children()));
childrow[cols.col_id] = 2982;
childrow[cols.col_name] = "Uber-Cleaner";
childrow[cols.col_market_share] = 67;

//Wir fuegen die Spalten hinzu
comboBox.pack_start(cols.col_name);

//Die Spalte Marktanteil soll als Fortschrittsbalken dargestellt werden
//Zuerst legen wir einen entsprechenden CellRenderer an

Gtk::CellRendererProgress *cell = new Gtk::CellRendererProgress;

//Wir fuegen den CellRenderer bzw. die Spalte hinzu
comboBox.pack_start(*cell);

//Und sagen dann, woher die Informationen kommen, die dargestellt werden
if (cell) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
comboBox.add_attribute(cell->property_value(), cols.col_market_share);
#else

comboBox.add_attribute(*cell, "value", cols.col_market_share);
#endif

}

//Erstes Element soll vorselektiert sein
comboBox.set_active(0);

//Verknuepfung des Signalhandlers
comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

//Hinzufuegen der Komponenten
topBox.pack_start(comboBox);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_market_share);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<int> col_market_share;
    };

    Gtk::VBox topBox;

    Gtk::ComboBox comboBox;
    Glib::RefPtr<Gtk::TreeStore> treeStore;

    Columns cols;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        Gtk::TreeModel::iterator iter = comboBox.get_active();
        if (iter) {
            Gtk::TreeModel::Row row = *iter;
            if (row) {
                std::cout    <<"ID: "<<row[cols.col_id]<<'\n'
                            <<"Name: "<<row[cols.col_name]<<'\n'
                            <<"Marktanteil: "<<row[cols.col_market_share]<<std::endl;
            }
        }
    }

    public:
    Application() {
        set_title("Gtk::ComboBox Example");
        set_default_size(300,25);

        //Wir erstellen das TreeStore und weisen es dem TreeView zu
        comboBox.set_model(treeStore = Gtk::TreeStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        //Ein Knoten auf der ersten Ebene

        Gtk::TreeModel::Row row = *(treeStore->append());
        row[cols.col_id] = 2000;
        row[cols.col_name] = "Elektrogeräte";
        row[cols.col_market_share] = 23;

        //Drei Subknoten
        Gtk::TreeModel::Row childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2485;
        childrow[cols.col_name] = "Staubsauger";
        childrow[cols.col_market_share] = 40;
       
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2751;
        childrow[cols.col_name] = "Mixer";
        childrow[cols.col_market_share] = 10;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Waschmaschine";
        childrow[cols.col_market_share] = 20;

        //Wieder ein Knoten auf Ebene 1
        row = *(treeStore->append());
        row[cols.col_id] = 3000;
        row[cols.col_name] = "Reinigungsmittel";
        row[cols.col_market_share] = 32;

        //Und drei Subknoten
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3149;
        childrow[cols.col_name] = "Brof";
        childrow[cols.col_market_share] = 12;
   
        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 3587;
        childrow[cols.col_name] = "Kill it!";
        childrow[cols.col_market_share] = 19;

        childrow = *(treeStore->append(row.children()));
        childrow[cols.col_id] = 2982;
        childrow[cols.col_name] = "Uber-Cleaner";
        childrow[cols.col_market_share] = 67;

        //Wir fuegen die Spalten hinzu
        comboBox.pack_start(cols.col_name);

        //Die Spalte Marktanteil soll als Fortschrittsbalken dargestellt werden
        //Zuerst legen wir einen entsprechenden CellRenderer an

        Gtk::CellRendererProgress *cell = new Gtk::CellRendererProgress;

        //Wir fuegen den CellRenderer bzw. die Spalte hinzu
        comboBox.pack_start(*cell);

        //Und sagen dann, woher die Informationen kommen, die dargestellt werden
        if (cell) {
#ifndef
GLIBMM_PROPERTIES_ENABLED
            comboBox.add_attribute(cell->property_value(), cols.col_market_share);
#else

            comboBox.add_attribute(*cell, "value", cols.col_market_share);
#endif

        }

        //Erstes Element soll vorselektiert sein
        comboBox.set_active(0);
       
        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}




Nun ja, alles in allem sieht das jetzt so alleine auf weiter Flur nicht besonders schön aus, aber es zeigt, was alles mit Gtk::ComboBox möglich ist. Gleichzeitig zeigt es aber auch, dass dieses Widget in den allermeisten Fällen totaler Overkill ist, da man häufig nur eine einzige Spalte mit Text für die Einträge braucht. Hier kommt Gtk::ComboBoxText ins Spiel:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    Gtk::VBox topBox;
    Gtk::ComboBoxText comboBox;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        std::cout<<"Auswahl: "<<comboBox.get_active_text()<<std::endl;
    }

    public:
    Application() {
        set_title("Gtk::ComboBoxText Example");
        set_default_size(220,25);

        //Wir fuegen noch ein paar Daten ein
        comboBox.append_text("Led Zeppelin");
        comboBox.append_text("Deep Purple");
        comboBox.append_text("The Doors");

        //Erstes Element soll vorselektiert sein
        comboBox.set_active(0);
       
        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
Gtk::VBox topBox;
Gtk::ComboBoxText comboBox;

protected:
//Signalhandler der reagiert, sobald sich die Auswahl aendert
virtual void on_combo_changed() {
std::cout<<"Auswahl: "<<comboBox.get_active_text()<<std::endl;
}

public:
Application() {
set_title("Gtk::ComboBoxText Example");
set_default_size(220,25);

//Wir fuegen noch ein paar Daten ein
comboBox.append_text("Led Zeppelin");
comboBox.append_text("Deep Purple");
comboBox.append_text("The Doors");

//Erstes Element soll vorselektiert sein
comboBox.set_active(0);

//Verknuepfung des Signalhandlers
comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

//Hinzufuegen der Komponenten
topBox.pack_start(comboBox);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    Gtk::VBox topBox;
    Gtk::ComboBoxText comboBox;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        std::cout<<"Auswahl: "<<comboBox.get_active_text()<<std::endl;
    }

    public:
    Application() {
        set_title("Gtk::ComboBoxText Example");
        set_default_size(220,25);

        //Wir fuegen noch ein paar Daten ein
        comboBox.append_text("Led Zeppelin");
        comboBox.append_text("Deep Purple");
        comboBox.append_text("The Doors");

        //Erstes Element soll vorselektiert sein
        comboBox.set_active(0);
       
        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}




Wie man sieht, hat sich die ganze Geschichte dadurch erheblich vereinfacht. :)

2.2 Gtk::ComboBoxEntry und Gtk::ComboBoxEntryText

Die in diesem Abschnitt behandelten ComboBoxen unterscheiden sich wie gesagt nur in einem Punkt von den anderen beiden: Sie ermöglichen die Eingabe von Text via Textfeld, um so auch andere Werte als die vorgegebenen anzugeben.

Zuerst ein Beispiel mit dem Gtk::ComboBoxEntry-Widget:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::ComboBoxEntry comboBox;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    void on_combo_changed() {
        std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
    }

    public:
    Application() {
        set_title("ComboBoxEntry Example");
        set_default_size(350,25);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        comboBox.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 2485;
        row[cols.col_name] = "Staubsauger";
        row[cols.col_price] = 79.99f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2751;
        row[cols.col_name] = "Mixer";
        row[cols.col_price] = 25.75f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2982;
        row[cols.col_name] = "Waschmaschine";
        row[cols.col_price] = 699.99f;
        row[cols.col_stock] = false;

        //Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
        comboBox.pack_start(cols.col_id);
        comboBox.pack_start(cols.col_price);
        comboBox.pack_start(cols.col_stock);

        //Auf welche Spalte sich die Eingabe beziehen soll...
        comboBox.set_text_column(cols.col_name);

        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Wir weisen die ComboBox dem ScrollWindow zu
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
//Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
class Columns : public Gtk::TreeModel::ColumnRecord {
public:
Columns() {
add(col_id);
add(col_name);
add(col_price);
add(col_stock);
}

~Columns() {}

Gtk::TreeModelColumn<unsigned> col_id;
Gtk::TreeModelColumn<Glib::ustring> col_name;
Gtk::TreeModelColumn<float> col_price;
Gtk::TreeModelColumn<bool> col_stock;
};

Gtk::VBox topBox;

//Hier die drei wichtigsten Komponenten
Gtk::ScrolledWindow scrollWindow;
Gtk::ComboBoxEntry comboBox;
Glib::RefPtr<Gtk::ListStore> listStore;

Columns cols;

protected:
//Signalhandler der reagiert, sobald sich die Auswahl aendert
void on_combo_changed() {
std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
}

public:
Application() {
set_title("ComboBoxEntry Example");
set_default_size(350,25);

//Wir erstellen das ListStore und weisen es dem TreeView zu
comboBox.set_model(listStore = Gtk::ListStore::create(cols));

//Wir fuegen noch ein paar Daten ein
Gtk::TreeModel::Row row = *(listStore->append());
row[cols.col_id] = 2485;
row[cols.col_name] = "Staubsauger";
row[cols.col_price] = 79.99f;
row[cols.col_stock] = true;

row = *(listStore->append());
row[cols.col_id] = 2751;
row[cols.col_name] = "Mixer";
row[cols.col_price] = 25.75f;
row[cols.col_stock] = true;

row = *(listStore->append());
row[cols.col_id] = 2982;
row[cols.col_name] = "Waschmaschine";
row[cols.col_price] = 699.99f;
row[cols.col_stock] = false;

//Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
comboBox.pack_start(cols.col_id);
comboBox.pack_start(cols.col_price);
comboBox.pack_start(cols.col_stock);

//Auf welche Spalte sich die Eingabe beziehen soll...
comboBox.set_text_column(cols.col_name);

comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

//Wir weisen die ComboBox dem ScrollWindow zu
topBox.pack_start(comboBox);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    //Wir definieren hier unsere Spalten bzw. wie eine Zeile aussieht
    class Columns : public Gtk::TreeModel::ColumnRecord {
    public:
        Columns() {
            add(col_id);
            add(col_name);
            add(col_price);
            add(col_stock);
        }
   
        ~Columns() {}
   
        Gtk::TreeModelColumn<unsigned> col_id;
        Gtk::TreeModelColumn<Glib::ustring> col_name;
        Gtk::TreeModelColumn<float> col_price;
        Gtk::TreeModelColumn<bool> col_stock;
    };

    Gtk::VBox topBox;

    //Hier die drei wichtigsten Komponenten
    Gtk::ScrolledWindow scrollWindow;
    Gtk::ComboBoxEntry comboBox;
    Glib::RefPtr<Gtk::ListStore> listStore;

    Columns cols;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    void on_combo_changed() {
        std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
    }

    public:
    Application() {
        set_title("ComboBoxEntry Example");
        set_default_size(350,25);

        //Wir erstellen das ListStore und weisen es dem TreeView zu
        comboBox.set_model(listStore = Gtk::ListStore::create(cols));

        //Wir fuegen noch ein paar Daten ein
        Gtk::TreeModel::Row row = *(listStore->append());
        row[cols.col_id] = 2485;
        row[cols.col_name] = "Staubsauger";
        row[cols.col_price] = 79.99f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2751;
        row[cols.col_name] = "Mixer";
        row[cols.col_price] = 25.75f;
        row[cols.col_stock] = true;

        row = *(listStore->append());
        row[cols.col_id] = 2982;
        row[cols.col_name] = "Waschmaschine";
        row[cols.col_price] = 699.99f;
        row[cols.col_stock] = false;

        //Nun muessen wir noch angeben, welche Spalten angezeigt werden sollen
        comboBox.pack_start(cols.col_id);
        comboBox.pack_start(cols.col_price);
        comboBox.pack_start(cols.col_stock);

        //Auf welche Spalte sich die Eingabe beziehen soll...
        comboBox.set_text_column(cols.col_name);

        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Wir weisen die ComboBox dem ScrollWindow zu
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}




Das einzige, was man bei Gtk::ComboBoxEntry beachten muss, ist dass man per m_combo.set_text_column(Columns::col_name); angeben muss, welche Spalte den Text beinhaltet. Diese Spalte wird bei diesem Aufruf auch gleich zum Gtk::ComboBoxEntry-Widget hinzugefügt. Das heißt, man sollte nicht auch noch pack_start auf diese Spalte anwenden, weil sie sonst zweimal vorkommt.

Abschließend wollen wir uns noch das Gtk::ComboBoxEntryText-Widget anschauen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    Gtk::VBox topBox;
    Gtk::ComboBoxEntryText comboBox;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
    }

    public:
    Application() {
        set_title("Gtk::ComboBoxEntryText Example");
        set_default_size(220,25);

        //Wir fuegen noch ein paar Daten ein
        comboBox.append_text("Led Zeppelin");
        comboBox.append_text("Deep Purple");
        comboBox.append_text("The Doors");

        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
Gtk::VBox topBox;
Gtk::ComboBoxEntryText comboBox;

protected:
//Signalhandler der reagiert, sobald sich die Auswahl aendert
virtual void on_combo_changed() {
std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
}

public:
Application() {
set_title("Gtk::ComboBoxEntryText Example");
set_default_size(220,25);

//Wir fuegen noch ein paar Daten ein
comboBox.append_text("Led Zeppelin");
comboBox.append_text("Deep Purple");
comboBox.append_text("The Doors");

//Verknuepfung des Signalhandlers
comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

//Hinzufuegen der Komponenten
topBox.pack_start(comboBox);
add(topBox);

show_all_children();
}
~Application() { }
};

int main(int argc, char **argv) {
Gtk::Main m(argc, argv);

Application app;
m.run(app);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include
<gtkmm.h>

class Application : public Gtk::Window {
    Gtk::VBox topBox;
    Gtk::ComboBoxEntryText comboBox;

    protected:
    //Signalhandler der reagiert, sobald sich die Auswahl aendert
    virtual void on_combo_changed() {
        std::cout<<"Auswahl: "<<(comboBox.get_entry())->get_text()<<std::endl;
    }

    public:
    Application() {
        set_title("Gtk::ComboBoxEntryText Example");
        set_default_size(220,25);

        //Wir fuegen noch ein paar Daten ein
        comboBox.append_text("Led Zeppelin");
        comboBox.append_text("Deep Purple");
        comboBox.append_text("The Doors");

        //Verknuepfung des Signalhandlers
        comboBox.signal_changed().connect(sigc::mem_fun(*this, &Application::on_combo_changed));

        //Hinzufuegen der Komponenten
        topBox.pack_start(comboBox);
        add(topBox);

        show_all_children();
    }
    ~Application() { }
};

int main(int argc, char **argv) {
    Gtk::Main m(argc, argv);

    Application app;
    m.run(app);

    return EXIT_SUCCESS;
}




3 Referenzen

[1] Tutorial zu Gtk::TreeView
[2] Gtk::TreeView Übersicht
[3] Gtk::CellRenderer Hierarchie
[4] Tutorial zu den Gtk::ComboBoxen


Zuletzt bearbeitet von estartu am 08:40:06 14.05.2008, insgesamt 3-mal bearbeitet
*-star@home-*
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.10.2007
Beiträge: 26
Beitrag *-star@home-* Mitglied 16:14:17 12.03.2008   Titel:              Zitieren

Hallo,

weißt du (oder jemand anders), wie man schnell und einfach die "liststore"-spalten durch 'nen klick sortieren kann?
Ich find das fehltin dem beispiel, sonst ein fettes:

Danke!
GPC
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 6310
Beitrag GPC Moderator 17:42:14 12.03.2008   Titel:              Zitieren

In dem von mir unter [1] verlinkten Tutorial findet sich ein Abschnitt darüber: http://gtkmm.org/docs/gtkmm-2.4/docs/tutorial/html/sec-treeview-sort.html

_________________
"We're rockstars, not lumberjacks" (Axl Rose about Grunge)
*-star@home-*
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.10.2007
Beiträge: 26
Beitrag *-star@home-* Mitglied 09:08:30 17.03.2008   Titel:              Zitieren

Hab ich total überlesen, danke!
C/C++ Forum :: Die Artikel ::  GTKmm Tutorial Teil 5   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.