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.
// 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);
// 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);
// 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);
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:
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
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
Sollte der Bereich leer sein, sprich wenn keine Auswahl vorhanden ist, gibt die Methode "get_selection_bounds" false zurück, andernfalls wird via
C/C++ Code:
m_textbuffer->apply_tag(tag, begin, end);
C/C++ Code:
m_textbuffer->apply_tag(tag, begin, end);
C/C++ Code:
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/C++ Code:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark(iterator_pos);
C/C++ Code:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark(iterator_pos);
C/C++ Code:
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/C++ Code:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark("LesezeichenName", iterator_pos);
C/C++ Code:
Glib::RefPtr<Gtk::TextBuffer::Mark> mark = m_textbuffer.create_mark("LesezeichenName", iterator_pos);
C/C++ Code:
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!
Sehr gelungener, informativer Artikel! Detailliert beschrieben, jedoch nicht unnötig überladen. Das einzige, was mich momentan noch etwas irritiert, ist das Konzept von GTKmm - überhaupt nicht vergleichbar mit wxWidgets z.B.. Aber diese Artikelserie macht es mir um einiges leichter, mich in diese Library einzuarbeiten.
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.
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.