Dieser und noch weitere Artikel wurde von evilissimo erstellt.


Folgende Themen werden von diesem Artikel berührt:


Druckversion des Artikels


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

1 Gtk::ScrolledWindow

Ein Gtk::ScrolledWindow ist ein Container-Widget, welches Scrollbalken für diverse Widgets anbietet. Meistens verwendet man dass Gtk::ScrolledWindow für Gtk::TreeView (bespreche ich in einem anderem Teil) und das Gtk::TextView, welches dieses mal das Hauptthema ist.

Es kommt zwar selten vor, aber manchmal findet das Gtk::ScrolledWindow Verwendung für die Gtk::DrawingArea, welche zum Zeichnen verwendet wird. Ich werde auf die Gtk::DrawingArea in meinem Tutorial warscheinlich überhaupt nicht weiter zu sprechen kommen. Sollte jemand Interesse an diesem Widget haben, da er selbst etwas zeichnen möchte, empfehle ich diesem die gtkmm Dokumentationsseiten [1]

Die wichtigsten Methoden die man von Gtk::ScrolledWindow kennen sollte sind die Methode add(), um ein Widget hinzuzufügen und set_policy(). set_policy() verwendet man um anzugeben wie sich die Scrollbalken verhalten sollen. Ob sie immer sichtbar sein sollen (Gtk::POLICY_ALWAYS), ob sie niemals sichtbar sein sollen (Gtk::POLICY_NEVER) oder ob sie automatisch angezeigt werden sollen wenn das Widget zu groß wird (Gtk::POLICY_AUTOMATIC).

Man kann das Verhalten für den horizontalen und den vertikalen Scrollbalken festlegen.

Viel mehr muss man meines Erachtens gar nicht über das Gtk::ScrolledWindow wissen. Deswegen höre ich hier mit dem Thema auf und komme gleich zum Nächsten.

2 Gtk::TextView

Das Gtk::TextView bietet vielseitige Möglichkeiten um Text darstellen zu können, es ist aber auch möglich Bilder oder andere Widgets einzufügen. Aufgrund seiner Vielfältigkeit werde ich nur ein paar grundlegende Features erklären.

Grundsätzlich braucht man für ein Gtk::TextView drei Dinge: Ein Gtk::ScrolledWindow, ein Gtk::TextBuffer und das Gtk::TextView selbst.

2.1 Simples TextView Beispiel

C++:
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
#include <gtkmm.h>
 
struct TextViewTutorial : public Gtk::Window
{
    TextViewTutorial();
    ~TextViewTutorial();
 
private:
    Gtk::ScrolledWindow           m_scrolled_window;
    Gtk::TextView                 m_textview;
    Glib::RefPtr<Gtk::TextBuffer> m_textbuffer;
};
 
TextViewTutorial::TextViewTutorial()
{
    // Fenstergröße setzen
    set_size_request(400,200);
 
    // Titel setzen
    set_title("GTKmm Tutorial Teil 4");
 
    // Textpuffer erstellen
    m_textbuffer = Gtk::TextBuffer::create();
 
    // Wir wollen das die Balken automatisch angezeigt werden, sobald mehr Text
    // vorhanden ist als in den Anzeigebereich passt
    m_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
 
    // Textpuffer setzen
    m_textview.set_buffer(m_textbuffer);
 
    // Textview dem ScrolledWindow hinzufügen
    m_scrolled_window.add(m_textview);
 
    // ScrolledWindow dem Fenster hinzufügen
    add(m_scrolled_window);
 
    // Alle Widgets anzeigen
    show_all_children();
}
 
TextViewTutorial::~TextViewTutorial()
{
}
 
int main(int argc, char **argv)
{
    Gtk::Main main(argc,argv);
    TextViewTutorial window;
    main.run(window);
    return EXIT_SUCCESS;
}




2.2 Textformatierungen

Wie man am obigen Beispiel gut erkennen kann, ist das Anlegen eines TextViews sehr simpel.
Interessanter wird es wenn man Text formatieren möchte. Hierzu werden "Tags" definiert, welche eine Formatierung des Textes definieren.
Man kann mehrere dieser Tags anlegen und mit Namen versehen. Zusätzlich können mehrere Tags auf den gleichen Text angewandt werden.

Mit Tags kann man unter anderem folgende Formatierungen setzen:
- Schriftart
- Schriftgröße
- Hintergrundfarbe
- Textfarbe
- Textstil (wie z.B. Kursiv, Fett, Unterstrichen etc. mit diversen Abstufungen)
...

Für noch mehr Möglichkeiten lohnt sich ein Blick in die Dokumentation.

Nun zu einem Beispiel, wie man diese Tags verwendet:
C++:
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
#include <gtkmm.h>
 
struct TextViewTutorial : public Gtk::Window
{
    TextViewTutorial();
    ~TextViewTutorial();
 
private:
    typedef Glib::RefPtr<Gtk::TextBuffer::Tag> TextTagPtr;
 
    Gtk::ScrolledWindow           m_scrolled_window;
    Gtk::TextView                 m_textview;
    Glib::RefPtr<Gtk::TextBuffer> m_textbuffer;
    Gtk::HBox                     m_hbox;
    Gtk::VButtonBox               m_vbuttonbox;
 
    Gtk::Button                   m_bold;
    Gtk::Button                   m_color;
    Gtk::Button                   m_underline;
    Gtk::Button                   m_italic;
 
    void apply_tag(TextTagPtr tag);
    void attach_signal(Gtk::Button & b, TextTagPtr const & tag);
};
 
void TextViewTutorial::attach_signal(Gtk::Button & b, TextTagPtr const & tag)
{
    b.signal_clicked().connect(sigc::bind<TextTagPtr>(sigc::mem_fun(this, &TextViewTutorial::apply_tag), tag));
}
 
void TextViewTutorial::apply_tag(TextTagPtr tag)
{
    Gtk::TextBuffer::iterator begin, end;
    if(m_textbuffer->get_selection_bounds(begin, end))
    {
        m_textbuffer->apply_tag(tag, begin, end);
    }
}
 
TextViewTutorial::TextViewTutorial()
{
    // Fenstergröße setzen
    set_size_request(400,200);
 
    // Titel setzen
    set_title("GTKmm Tutorial Teil 4 - Textformatierung"); 
 
    // Textpuffer erstellen
    m_textbuffer = Gtk::TextBuffer::create();
 
    // Wir wollen das die Balken automatisch angezeigt werden, sobald mehr Text
    // vorhanden ist als in den Anzeigebereich passt
    m_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
 
    // Textpuffer setzen
    m_textview.set_buffer(m_textbuffer);
 
    // Textview dem ScrolledWindow hinzufügen
    m_scrolled_window.add(m_textview);
   
    // Erstellung der Tags und Definition der Formatierungen
    // Rote Schrift
    TextTagPtr color_tag = Gtk::TextBuffer::Tag::create("color");
    color_tag->property_foreground() = "red";
 
    // Fettschrift
    TextTagPtr bold_tag = Gtk::TextBuffer::Tag::create("bold");
    bold_tag->property_weight() = 900;
 
    // Kursive Schrift
    TextTagPtr italic_tag = Gtk::TextBuffer::Tag::create("italic");
    italic_tag->property_style() = Pango::STYLE_ITALIC;
 
    // Unterstrichener Text
    TextTagPtr underlined_tag = Gtk::TextBuffer::Tag::create("underlined");
    underlined_tag->property_underline() = Pango::UNDERLINE_SINGLE;
 
    // Buttonbeschriftung setzen und signal verbinden
    m_color.set_label("Farbe");
    attach_signal(m_color, color_tag);
    m_bold.set_label("Fett");
    attach_signal(m_bold, bold_tag);
    m_italic.set_label("Kursiv");
    attach_signal(m_italic, italic_tag);
    m_underline.set_label("Unterstrichen");
    attach_signal(m_underline, underlined_tag);
 
    // Tags dem TextPuffer bekannt machen
    m_textbuffer->get_tag_table()->add(color_tag);
    m_textbuffer->get_tag_table()->add(bold_tag);
    m_textbuffer->get_tag_table()->add(italic_tag);
    m_textbuffer->get_tag_table()->add(underlined_tag);
 
    // Buttons der ButtonBox übergeben
    m_vbuttonbox.pack_start(m_color);
    m_vbuttonbox.pack_start(m_bold);
    m_vbuttonbox.pack_start(m_italic);
    m_vbuttonbox.pack_start(m_underline);
 
    // ScrolledWindow dem Layout hinzufügen
    m_hbox.pack_start(m_scrolled_window);
    // Button box dem Layout hinzufügen
    m_hbox.pack_start(m_vbuttonbox, Gtk::PACK_SHRINK, 10);
 
    // Layout setzen
    add(m_hbox);
 
    // Alle Widgets anzeigen
    show_all_children();
}
 
TextViewTutorial::~TextViewTutorial()
{
}
 
int main(int argc, char **argv)
{
    Gtk::Main main(argc,argv);
    TextViewTutorial window;
    main.run(window);
    return EXIT_SUCCESS;
}


Eine kleine Erklärung des Codes:
In diesem Beispiel werden vier Tags definiert "color", "bold", "italic" und "underlined". Diese vier Tags können mit den Buttons gesetzt werden, indem man den eingegebenen Text auswählt und einen oder eventuell auch mehrere Buttons anklickt.

Nun noch eine Erklärung der "attach_signal" Methode: Diese Methode setzt den Signalhandler für die übergebene Schaltfläche und bindet das übergebene Tag an den Aufruf, somit kann man einen Handler für alle Buttons verwenden und muss nicht vier verschiedene schreiben.

Die Methode "apply_tag", welche durch einen Klick auf einen Button ausgelöst wird, holt sich zunächst den Auswahlbereich über
C++:
if(m_textbuffer->get_selection_bounds(begin, end))

Sollte der Bereich leer sein, sprich wenn keine Auswahl vorhanden ist, gibt die Methode "get_selection_bounds" false zurück, andernfalls wird via
C++:
m_textbuffer->apply_tag(tag, begin, end);
das übergebene Tag auf den ausgewählten Bereich angewandt.

Und so sieht's aus:


2.3 Weiterführendes zum Thema

Wenn Ihr den Inhalt des TextView Puffers lesen oder ändern möchtet, wird dies mit Hilfe der Iteratoren erledigt. Iteratoren sind aber nur gültig solange der TextBuffer nicht verändert wurde.

Manchmal möchte man sich aber eine bestimmte Position im Text merken. Hierfür bietet gtkmm sogenannte TextMarks an, mit welchen man an einer bestimmten Stelle im Text ein "Lesezeichen" setzen kann. Diese Lesezeichen können mit der Methode create_mark() erstellt werden.
C++:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark(iterator_pos);


Man kann diese Lesezeichen auch benennen, damit kann man umgehen das man die Instanzen der Klasse TextMark herumreichen muss. Um ein benanntes Lesezeichen zu erstellen geht geht man folgenermaßen vor:
C++:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark("LesezeichenName", iterator_pos);


Zusätzlich gibt es noch einen weiteren Parameter bei der Erstellung einer Textmarke: "left_gravity", welcher per Voreinstellung auf true gesetzt ist.
Dieser Parameter gibt an, in welche Richtung sich die Textmarke beim Einfügen vom Text verschiebt.

Hinweis am Rande: Bei Sprachen die Rechts-nach-Links gelesen werden ist "left_gravity" automatisch umgedreht, das heißt es verhält sich genauso zum Text wie bei den in westlichen Ländern verwendeten Eingabeschemata.

Es sind noch viel mehr Dinge mit Gtk::TextView möglich, jedoch würde dies den Rahmen eines Einsteiger Tutorials bei weitem überschreiten.
Für nähere Infos zu diesem Thema schlagt einfach in der unten verlinkten Dokumentation nach.

Im Folgenden noch eine kurze Zusammenfassung, was man so alles mit einer Gtk::TextView anstellen kann:
- Ihr könnt mit der Zwischenablage arbeiten, um Text auszulesen, auszuschneiden, oder zu kopieren
- Ihr könnt Bilder und sogar andere Widgets wie Buttons, Checkboxen etc. einfügen (z.b. um eine einem Webbrowser ähnliche Funktionalität zu erzeugen)
- Ihr habt unzählige Möglichkeiten zur Textformatierung: Größe, Dicke, Farbe, Ausrichtung u.v.m.

Das Interface zu der Funktionalität ist eigentlich für die Fülle der Möglichkeiten recht kompakt und meines Erachtens nach schnell zu verstehen, auch wenn einen die dazugehörigen Methoden/Klassen auf den ersten Blick erschlagen mögen.

Okay, ich hoffe Ihr hattet Spaß daran den Code zu lesen und ich hoffe es hat euch zu neuen Programmierideen inspiriert :)

Da ich momentan etwas Zeit habe, werde ich mich auch gleich an den nächsten Teil machen, damit Ihr auch bald wieder was zum Thema zu lesen habt!

Grüße aus der Tschechischen Republik,

Vinzenz 'evilissimo' Feenstra ;)

Referenzen:

[1] GTKmm Dokumentationsseiten

Sie können Kommentare zu diesem Artikel im Forum schreiben. (Eine Registrierung ist nicht notwendig.)

Logo-Design: MastaMind Webdesign