Helmut Herold: Das Qt-Buch - Technische Hochschule Nürnberg
Transcrição
Helmut Herold: Das Qt-Buch - Technische Hochschule Nürnberg
Helmut Herold: Das Qt-Buch Helmut Herold Das Qt-Buch Portable GUI-Programmierung unter Linux / Unix / Windows Alle in diesem Buch enthaltenen Programme, Darstellungen und Informationen wurden nach bestem Wissen erstellt und mit Sorgfalt getestet. Dennoch sind Fehler nicht ganz auszuschließen. Aus diesem Grund ist das in dem vorliegenden Buch enthaltene ProgrammMaterial mit keiner Verpflichtung oder Garantie irgendeiner Art verbunden. Autoren und die SuSE GmbH übernehmen infolgedessen keine Verantwortung und werden keine daraus folgende Haftung übernehmen, die auf irgendeine Art aus der Benutzung dieses Programm-Materials, oder Teilen davon, oder durch Rechtsverletzungen Dritter entsteht. Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Buch berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann verwendet werden dürften. Alle Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt und sind möglicherweise eingetragene Warenzeichen. Die SuSE GmbH richtet sich im Wesentlichen nach den Schreibweisen der Hersteller. Andere hier genannte Produkte können Warenzeichen des jeweiligen Herstellers sein. Dieses Werk ist urheberrechtlich geschützt. Alle Rechte, auch die der Übersetzung, des Nachdruckes und der Vervielfältigung des Buches, oder Teilen daraus, vorbehalten. Kein Teil des Werkes darf ohne schriftliche Genehmigung des Verlages in irgendeiner Form (Druck, Fotokopie, Microfilm oder einem anderen Verfahren), auch nicht für Zwecke der Unterrichtsgestaltung, reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, vervielfältigt oder verbreitet werden. Die Deutsche Bibliothek – CIP-Einheitsaufnahme Herold, Helmut: Das Qt-Buch : portable GUI-Programmierung unter Linux/Unix/Windows / Helmut Herold. – Nürnberg : SuSE-Press, 2001 ISBN 3-934678-76-9 © 2001 SuSE GmbH, Nürnberg (http://www.suse.de) Umschlaggestaltung: Fritz Design GmbH, Erlangen Gesamtlektorat: Nicolaus Millin / Dr. Markus Wirtz Fachlektorat: Michael Eicks, Stefan Fent, Thomas Fricke, Bruno Gerz, Ralf Haferkamp, Michael Hager, Harri Porten, Chris Schläger, Lukas Tinkl Satz: LATEX Druck: Kösel, Kempten Printed in Germany on acid free paper. Geleitwort Wenn wir bei Trolltech an Qt denken, so denken wir an ein Werkzeug für „real programmers“. Dies bedeutet keinesfalls, dass wir noch mit Fortran arbeiten oder unser API nicht dokumentieren. „Real programmers“ sind für uns Profis, die ihre Arbeit gemacht bekommen müssen – schnell, effizient und mit wartbarem Code in bestmöglicher Qualität. „Real programmers“ springen nicht auf den letzen Hype auf – wie auch immer die Programmiersprache des Monats oder das Dogma der Woche lauten sollten. Für sie zählt Ausführungsgeschwindigkeit, Eleganz, Wartbarkeit, Flexibilität und nicht zuletzt die eigene Effizienz bei der Entwicklung der Programme. Für immer mehr Projekte bedeutet das fast schon automatisch Qt und C ++. Verglichen mit alternativen Toolkits benötigt eine mit Qt geschriebene Anwendung in der Regel nur einen Bruchteil des Codes, ohne dabei langsamer zu sein. Wohlgemerkt, das gilt bereits für eine einzige Plattform, für cross-platform Anwendungen fällt das Ergebnis für Qt noch viel günstiger aus. Unser Geheimrezept hierfür sind – neben der konsequenten Anwendung Objekt-orientierter Techniken – sorgfältig gestaltete APIs und Abstraktionen. Ziel ist es, die „normale“ Anwendung einer Klasse so einfach wie nur irgend möglich zu machen, ohne dabei die avanciertere Verwendung zu erschweren. Das setzt voraus, dass sich ein Toolkit nicht als Blackbox präsentiert, sondern als offene Lösung auch die dahinterliegenden Konzepte offenbart. Ein angenehmer Nebeneffekt soll hier nicht verschwiegen werden: Programmieren mit Qt macht einfach Spaß! Zumindest mir ging das vor fünf Jahren so, als ich das Toolkit erstmals als Anwender entdeckte – und bis heute hat sich daran nichts geändert. Und solange ich unsere Entwicklungsabteilung in ihrer Freizeit an privaten Qt-basierten Projekten basteln sehe, wird sich daran auch nichts ändern. Viel Spaß also auch Ihnen mit Qt und dem bis dato umfangreichsten gedruckten Werk zur Qt-Programmierung! Eine Bitte noch: Wenn sie einen Fehler in Qt gefunden oder einen Verbesserungsvorschlag zu machen haben, bitte zögern Sie nicht, uns eine Mail auf: [email protected] zu schicken. Oslo, im Juni 2001 Matthias Ettrich Danksagung Zunächst möchte ich einmal Nico Millin und Dr. Markus Wirtz von SuSE PRESS meinen Dank dafür aussprechen, dass sie beim Setzen dieses Buches mit über 1 000 Seiten nie den Mut verloren und immer nur positiv nach vorne – oder sagen wir in diesem Falle besser: nach hinten – geblickt haben. Trotz aller Widrigkeiten, die das Setzen eines Buches nun einmal mit sich bringt, war die Zusammenarbeit mit ihnen immer angenehm. Dafür möchte ich mich an dieser Stelle nochmals recht herzlich bedanken. Des weiteren möchte ich mich noch bei meinen Kollegen von SuSE Labs bedanken, die selbst in den größten Stresszeiten stets Zeit fanden, mir bei nervenden Fragen zu helfen, und mir mit Rat und Tat zur Seite standen. Ein dickes Dankeschön an Klaas Freitag, Michael Hager, Stefan Hundhammer, Chris Schläger und Adrian Schroeter. Auch möchte ich mich bei Michael Eicks, Stefan Fent, Thomas Fricke, Bruno Gerz, Ralf Haferkamp und Lukas Tinkl für ihre konstruktiven Beiträge und Anregungen während des Korrekturlesens herzlich bedanken, die ich sehr gerne in dieses Buch eingearbeitet habe. Schließlich möchte ich mich noch bei der norwegischen Firma Trolltech bedanken, ohne die es keine Qt-Bibliothek und somit auch nicht dieses Buch gäbe. Ein dickes Dankeschön an Matthias Ettrich und Harri Porten von Trolltech für ihre Unterstützung, auf die ich gerade in der Endphase der Entstehung dieses Buches angewiesen war. Und natürlich danke ich meiner Frau Micha, die meiner Sucht zum Schreiben dieses Buches mit mehr Verständnis und Entbehrung entgegenkam als ich verdient habe. Meinen beiden Kindern Niklas und Sascha möchte ich an dieser Stelle noch versprechen, dass wir jetzt wieder öfter Angeln gehen. Weisendorf-Neuenbürg, im Juni 2001 Dr. Helmut Herold Die Themen im Überblick Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 Einführung in die Objektorientierung und C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2 Allgemeines zu Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 3 Grundlegende Konzepte und Konstrukte von Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4 Die wesentlichen Qt-Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 5 Zuordnung und Layout von Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 6 Vordefinierte Dialogfenster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 7 Portable Datei- und Directory-Operationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485 8 Vordefinierte Datentypen und Datenstrukturen (Containerklassen) . . . . . . . . . 521 9 Datenaustausch zwischen verschiedenen Applikationen . . . . . . . . . . . . . . . . . . . 593 10 Datum, Zeit und Zeitschaltuhren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 11 Graphik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 12 Bildformate und Cursorformen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747 13 Animationen und Sounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775 14 Konsistente Eingaben und reguläre Ausdrücke . . . . . . . . . . . . . . . . . . . . . . . . . . . 789 15 Tastaturfokus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813 16 Ereignisbehandlung (Event-Handling) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 823 17 Signale und Slots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869 IX Die Themen im Überblick 18 Erstellen eigener Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881 19 Thread-Programmierung und -Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 20 Mehrsprachige Applikationen und Internationalisierung . . . . . . . . . . . . . . . . . . 943 21 Test- und Debugging-Möglichkeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 955 22 Netzwerkprogrammierung mit Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 23 Blockierungsfreie Datenübertragung im Hintergrund . . . . . . . . . . . . . . . . . . . . 1021 24 Parsen von XML-Dokumenten. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1027 25 Qt-Programmierung mit anderen Bibliotheken und Sprachen . . . . . . . . . . . . 1079 26 Der Qt GUI-Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1117 27 Erstellen von Qt-Programmen mit KDevelop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143 28 Das Tool tmake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 X Inhaltsverzeichnis Einleitung 1 1 Einführung in die Objektorientierung und C++ 1.1 Objektorientierung in der realen Welt . . . . . 1.2 Objektorientierung in der Software . . . . . 1.3 Nicht-objektorientierte Erweiterungen in C++ . . . 1.3.1 Zeilen-Kommentare mit // . . . . . . 1.3.2 Variablen-Deklarationen (auch im Anweisungsteil) . 1.3.3 Default-Argumente bei Funktionsaufrufen . . 1.3.4 Überladen von Funktionen . . . . . . 1.3.5 Inline-Funktionen . . . . . . . 1.3.6 Referenzen/Referenz-Operator . . . . . 1.3.7 Neue Ein- und Ausgabebibliothek . . . . 1.3.8 Operatoren new und delete . . . . . 1.3.9 Neuer Datentyp bool . . . . . . . 1.3.10 Weglassen der Schlüsselwörter struct, union und enum bei Deklarationen . . . . . . . . 1.3.11 Funktionen in Strukturen – Erster wesentlicher Schritt zur Objektorientierung . . . . . . . 1.3.12 Beispiel: Mastermind gegen Computer . . . 1.4 Objektorientierte Erweiterungen in C++ . . . . 1.4.1 Wichtige Begriffe aus der Welt der Objektorientierung 1.4.2 Klassen . . . . . . . . . . 1.4.3 Überladen von Operatoren . . . . . . 1.4.4 Vererbung . . . . . . . . . 1.4.5 Templates . . . . . . . . . 37 51 54 54 55 65 72 105 2 Allgemeines zu Qt 2.1 Was ist Qt und warum Qt? . . . . 2.2 Der Begriff „Widget“ . . . . . 2.3 Die Qt-Online-Dokumentation im HTML-Format 2.4 Die Qt-Dokumentation als Postscript-Datei . 2.5 Kompilieren von Qt-Programmen . . . 115 115 117 117 119 119 . . . . . . . . . . . . . . . 11 11 14 16 16 16 17 18 19 20 25 35 36 37 XI Inhaltsverzeichnis 3 Grundlegende Konzepte und Konstrukte von Qt 3.1 Erstes Qt-Programm mit Text und Buttons . . . . 3.2 Mehr zum Signal-Slot-Konzept von Qt . . . . . 3.2.1 Schiebebalken und Buttons zum Erhöhen/Erniedrigen von LCD-Nummern . . . . . . . . 3.2.2 Schiebebalken und Buttons zum Ändern der Schriftgröße mit Textanzeige . . . . . . . . . 3.2.3 Regeln für die Deklaration eigener Slots und Signale 3.3 Die Klasse QString für das Arbeiten mit Zeichenketten unter Qt 3.4 Farbmodelle, Farbgruppen und Paletten im Qt . . . 3.4.1 Farbmodelle (QColor) . . . . . . . 3.4.2 Farbgruppen (QColorGroup) . . . . . 3.4.3 Palette eines Widget (QPalette) . . . . 3.4.4 Beispiele . . . . . . . . . 3.5 Malprogramm mit Menüs, Events und mehr . . . . 3.5.1 Eine erste einfache Version eines Malprogramms . 3.5.2 Eine zweite, etwas erweiterte Version des Malprogramms 3.5.3 Eine dritte Version des Malprogramms mit Menüs . 3.5.4 Eine vierte Version des Malprogramms mit Laufbalken 3.5.5 Eine fünfte Version des Malprogramms mit einigen netten Erweiterungen . . . . . . . . 3.5.6 Eine letzte Version des Malprogramms mit Speichern und Laden von Dateien . . . . . . . 4 Die wesentlichen Qt-Widgets 4.1 Allgemeine Widget-Methoden und -Parameter . . . 4.1.1 Allgemeine Widget-Methoden . . . . . 4.1.2 Parameter-Konventionen für die meisten Konstruktoren 4.2 Der Widget-Stil . . . . . . . . . . 4.3 Buttons . . . . . . . . . . . 4.3.1 Pushbuttons (QPushButton) . . . . . 4.3.2 Radiobuttons (QRadioButton) und Checkboxen (QCheckBox) . . . . . . . . . . 4.3.3 Pushbuttons mit der Wirkungsweise von Radiobuttons 4.3.4 Gruppieren von Buttons (QButtonGroup) . . 4.3.5 Beispiel zu Buttons . . . . . . . 4.3.6 Beispiel zu Gruppen von Buttons . . . . 4.3.7 Beispiel zu Popupmenüs bei Pushbuttons . . . 4.3.8 Übung: Synchronisieren von Radio- mit Togglebuttons 4.4 Auswahl-Widgets (List- und Komboboxen) . . . . 4.4.1 Listboxen (QListBox) . . . . . . . 4.4.2 Komboboxen (QComboBox) . . . . . . 4.4.3 Beispiel zu List- und Komboboxen . . . . 4.4.4 Übung: Eingabe von Daten über List- und Komboboxen 4.5 Schiebebalken-, Drehknopf- und Spinbox-Widgets . . 4.5.1 Schiebebalken (QSlider) . . . . . . XII 123 124 128 128 131 135 137 146 146 149 150 152 160 160 165 166 171 178 189 199 201 201 202 203 204 204 205 205 206 207 210 213 216 216 216 218 219 223 223 224 Inhaltsverzeichnis 4.5.2 4.5.3 4.5.4 4.5.5 4.5.6 4.6 4.7 4.8 4.9 Drehknopfeinstellungen (QDial) . . . . Spinboxen (QSpinBox) . . . . . . Beispiel zu Schiebebalken und Spinboxen . . . Beispiel zur Klasse QDial . . . . . . Übung: Größeneinstellung eines Rechtecks über Schiebebalken und Spinboxen . . . . . . . Widgets zum Anzeigen von Informationen . . . . 4.6.1 Einfache Labels (QLabel) . . . . . . 4.6.2 Komfortable Textanzeige (QTextView, QTextBrowser) 4.6.3 7-Segment-LCD-Anzeige (QLCDNumber) . . . 4.6.4 Beispiel zu Labels: Anzeige von Graphikbildern . 4.6.5 Beispiel zur Anzeige von RichText . . . . 4.6.6 Beispiel zu LCD-Zahlen: Synchronisierte Darstellung in verschiedenen Zahlensystemen . . . . . 4.6.7 Übung: Mausposition als LCD-Nummer und als Fadenkreuz Texteingabefelder . . . . . . . . . 4.7.1 Einzeilige Texteingabefelder (QLineEdit) . . 4.7.2 Mehrzeilige Texteingabefelder (QMultiLineEdit) . 4.7.3 Beispiel zu Texteingabefeldern: Potenzieren von Zahlen 4.7.4 Weiteres Beispiel zu einzeiligen Texteingabefeldern . 4.7.5 Übung: Synchronisierte Darstellung in verschiedenen Zahlensystemen . . . . . . . . . Menüs . . . . . . . . . . . 4.8.1 Die Basisklasse für Menüs (QMenuData) . . . 4.8.2 Beispiel: Auswahl einer Farbe über ein Menü . . 4.8.3 Festlegen von Beschleunigern (Accelerators) . . 4.8.4 Popupmenüs, deren Inhalt sich dynamisch ändert . 4.8.5 Die Menüleiste (QMenuBar) . . . . . 4.8.6 Kontextmenüs . . . . . . . . 4.8.7 Beispiel zu Menüs . . . . . . . 4.8.8 Übung: Einstellen des Font über Menüs, Beschleuniger oder Kontextmenüs . . . . . . . . Hauptfenster mit Menüs, Werkzeugleisten, Statuszeile und Hilfstexten . . . . . . . . . . . . 4.9.1 Das Hauptfenster (QMainWindow) . . . . 4.9.2 Werkzeugleisten (QToolBar und QToolButton) . 4.9.3 Einfaches Beispiel zu QMainWindow mit Menüs und Werkzeugleisten . . . . . . . . . 4.9.4 Kurze und längere Hilfstexte (QToolTip, QToolTipGroup und QWhatsThis) . . . . . . . 4.9.5 Beispiel: Dynamische Tooltips (Möglichkeit 1) . . 4.9.6 Beispiel: Dynamische Tooltips (Möglichkeit 2) . . 4.9.7 Statuszeilen (QStatusBar) . . . . . . 4.9.8 Beispiel zu QMainWindow mit Werkzeugleisten, Statuszeile und Hilfstexten . . . . . . . . 4.9.9 Übung: Einfacher Texteditor . . . . . 225 227 228 231 235 235 235 236 237 238 239 243 246 246 246 247 249 251 254 254 255 256 258 259 259 259 260 264 264 265 267 268 271 272 275 279 280 289 XIII Inhaltsverzeichnis 4.10 Füllbalken . . . . . . . . . . . 4.10.1 Horizontaler Füllbalken (QProgressBar) . . 4.10.2 Dialog mit Text, Füllbalken und Cancel-Button (QProgressDialog) . . . . . . . . . 4.10.3 Beispiel: Demoprogramm zu QProgressDialog . 4.10.4 Übung: Steuern eines Füllbalkens über Schiebebalken 4.10.5 Übung: Würfeln der Gaußschen Glockenkurve . . 4.11 Listenansichten . . . . . . . . . 4.11.1 Die Klasse QListView . . . . . . 4.11.2 Die Klasse QListViewItem . . . . . 4.11.3 Die Klasse QListViewItemIterator . . . 4.11.4 Einfaches Beispiel zu einer Listenansicht . . . 4.11.5 Beispiel: Directorybrowser in Form einer Listenansicht 4.11.6 Übung: Qt-Klassenhierarchie in einer Listenansicht . 4.12 Fenster mit Laufbalken (Scrollviews) . . . . . 4.12.1 Die Klasse QScrollView . . . . . . 4.12.2 Vorgehensweisen abhängig von Fensterfläche . . 4.12.3 Beispiel zu den unterschiedlichen Vorgehensweisen . 4.12.4 Die Klasse QScrollBar . . . . . . 4.12.5 Beispiel: Scrollen eines Bildes mit QScrollBar . 4.12.6 Übung: Geschachtelte Fenster mit Laufbalken . . 4.13 Tabellen . . . . . . . . . . . 4.13.1 Die Klasse QTableView für einfache Tabellen . . 4.13.2 Beispiel zu QTableview: Multiplikationsaufgaben . 4.13.3 Die Klasse QTable für Tabellen im Spreadsheet-Stil . 4.13.4 Die Klasse QHeader . . . . . . . 4.13.5 Die Klassen QTableItem und QTableSelection . 4.13.6 Beispiel: Spreadsheet für eine Personalverwaltung . 4.13.7 Übung: Tabelle mit Multiplikationsaufgaben . . 5 Zuordnung und Layout von Widgets 5.1 Zuordnung von Widgets untereinander . . . 5.1.1 Die Klasse QFrame . . . . . 5.1.2 Die Klasse QGroupBox . . . . 5.1.3 Die Klasse QButtonGroup . . . . 5.1.4 Die Klasse QSplitter . . . . 5.1.5 Die Klasse QWidgetStack . . . . 5.2 Layout von Widgets . . . . . . . 5.2.1 Einfaches Layout mit QHBox, QVBox und QGrid 5.2.2 Fortgeschrittenes Layout mit QLayout . 5.2.3 Benutzerdefinierte Layouts . . . . 6 Vordefinierte Dialogfenster 6.1 Die Basisklasse QDialog . . . . . 6.2 Klasse QColorDialog zur Auswahl einer Farbe 6.3 Klasse QFileDialog zur Auswahl einer Datei XIV . . . . . . . . . . . . . . . 290 290 294 296 300 300 302 302 304 305 306 308 312 312 312 316 317 326 327 333 333 333 336 341 344 345 345 350 . . . . . . . . . . 351 352 352 358 363 363 370 373 374 377 397 . . . 417 418 421 423 Inhaltsverzeichnis 6.4 6.5 6.6 Klasse QFontDialog zur Auswahl eines Font . . . Klasse QMessageBox für Mitteilungen . . . . . Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat . . . . . . . . . . . 6.7 Klasse QWizard zum Blättern in einer vorgegebenen Menge von Widgets . . . . . . . . . . . 6.8 Klasse QPrinter zum Drucken mit möglichen Druckereinstellungen . . . . . . . . . . . . 6.9 Klasse QInputDialog für einfache Benutzereingaben . 6.10 Klasse QProgressDialog zur Fortschrittsanzeige in einem Prozentbalken . . . . . . . . . . 7 Portable Datei- und Directory-Operationen 7.1 Die Basisklasse QIODevice für Zugriffe auf E/A-Geräte . 7.2 Klasse QFile für Datei-Operationen . . . . . 7.3 Klasse QBuffer für Speicherzugriffe wie bei einem E/A-Gerät 7.4 Die Klassen QTextStream und QDataStream . . . 7.4.1 Klasse QTextStream zum Lesen und Schreiben von Text in Dateien . . . . . . . . . . 7.4.2 Klasse QDataStream zum plattformunabhängigen Lesen und Schreiben in Dateien . . . . . . . 7.5 Klasse QFileInfo zum Erfragen von Informationen zu Dateien 7.6 Klasse QDir für Directory-Operationen . . . . . 8 Vordefinierte Datentypen und Datenstrukturen (Containerklassen) 8.1 Vordefinierte Datentypen (QPoint, QSize und QRect) . 8.1.1 Die Klasse QPoint . . . . . . . 8.1.2 Die Klasse QSize . . . . . . . . 8.1.3 Die Klasse QRect . . . . . . . . 8.1.4 Übung: Durchschnitt und umschließendes Rechteck von zwei Rechtecken . . . . . . . . . 8.2 Data-Sharing . . . . . . . . . . 8.3 Arrays . . . . . . . . . . . 8.3.1 Die Klasse QArray . . . . . . . 8.3.2 Die Klasse QVector . . . . . . . 8.3.3 Die Klasse QByteArray . . . . . . 8.3.4 Die Klasse QBitArray . . . . . . 8.3.5 Die Klasse QPointArray . . . . . . 8.4 Hashtabellen und zugehörige Iterator-Klassen . . . 8.4.1 Die Klasse QDict . . . . . . . . 8.4.2 QDictIterator - Eine Iterator-Klasse für QDict . 8.4.3 Die Klassen QAsciiDict, QPtrDict, QAsciiDictIterator und QPtrDictIterator . . . . . 8.4.4 Die Klassen QIntDict und QIntDictIterator . 8.4.5 Die Klasse QCache . . . . . . . 8.4.6 QCacheIterator – Eine Iterator-Klasse für QCache 431 436 446 456 463 477 483 485 485 487 491 493 493 497 506 513 521 523 523 525 527 530 530 535 535 540 540 540 543 547 548 552 557 557 559 561 XV Inhaltsverzeichnis 8.4.7 Die Klassen QAsciiCache und QAsciiCacheIterator 8.4.8 Die Klassen QIntCache und QIntCacheIterator 8.4.9 Die Klasse QMap für wertebasierende Hashtabellen . 8.4.10 Übung: Cross-Reference-Liste für C-Programme . Listen und zugehörige Iterator-Klassen . . . . . 8.5.1 Die Klasse QList . . . . . . . . 8.5.2 QListIterator – Eine Iterator-Klasse für QList . 8.5.3 Klasse QValueList – Eine wertebasierende Liste . 8.5.4 Die Iterator-Klassen QValueListIterator und QValueListConstIterator . . . . . . 8.5.5 Die Klasse QStringList . . . . . . 8.5.6 Die Klassen QStrList und QStrIList . . . 8.5.7 Übung: Das Josephus-Spiel . . . . . . Stacks (LIFO-Strategie) . . . . . . . . 8.6.1 Die referenzbasierende Klasse QStack . . . 8.6.2 Die wertebasierende Klasse QValueStack . . 8.6.3 Übung: Umwandlung einer Dezimalzahl in Dualzahl Queues (FIFO-Strategie) . . . . . . . . 8.7.1 Die Klasse QQueue . . . . . . . 8.7.2 Beispiel: Simulation einer Warteschlange . . . 8.7.3 Übung: Realisierung einer Warteschlange . . . 562 562 563 566 567 567 571 573 9 Datenaustausch zwischen verschiedenen Applikationen 9.1 Verwendung des Clipboard . . . . . . . 9.1.1 Die Klasse QClipBoard . . . . . . 9.1.2 Beispiel: Austausch von Texten über das Clipboard . 9.1.3 Beispiel: Austausch von Bildern über das Clipboard 9.1.4 Übung: Zufälliges Austauschen von Bildern über das Clipboard . . . . . . . . . . 9.2 Drag-and-Drop . . . . . . . . . . 9.2.1 Drag-and-Drop von Text oder Bildern in Qt . . 9.2.2 Drag-and-Drop in Verbindung mit dem Clipboard . 9.2.3 Definieren von eigenen Typen für Drag-and-Drop . 9.2.4 Die Klasse QUriDrag zum Austausch von Dateinamen 9.2.5 Übung: Zusammenstellen eines Kartenblattes mit Drag-andDrop . . . . . . . . . . 593 593 594 594 596 8.5 8.6 8.7 10 Datum, Zeit und Zeitschaltuhren 10.1 Die Klasse QDate . . . . . . . . . 10.1.1 Beispiel: Demonstrationsprogramm zur Klasse QDate 10.1.2 Beispiel: Tagesdifferenz zwischen zwei Daten . . 10.1.3 Übung: Ermitteln des Ostertermins für ein Jahr . 10.2 Die Klasse QTime . . . . . . . . . 10.2.1 Beispiel: Addition von zwei Zeiten . . . . 10.2.2 Beispiel: Ein Reaktionstest . . . . . . 10.2.3 Übung: Anzeige der aktuellen Zeit mit Fortschrittsbalken XVI 575 577 580 582 582 582 584 586 587 587 588 591 598 598 598 607 609 615 615 617 617 619 621 622 623 624 625 628 Inhaltsverzeichnis 10.3 Die Klasse QDateTime . . . . . . . . 10.3.1 Beispiel: Ausgeben der Sekunden und Tage bis zu fixen Daten . . . . . . . . . . . 10.3.2 Übung: Automatische Arbeitszeiterfassung . . 10.4 Zeitschaltuhren (Timer) . . . . . . . . 10.4.1 Die Klasse QTimer . . . . . . . 10.4.2 Timer-Events . . . . . . . . 10.4.3 Übung: Realisierung einer Ampelsteuerung . . 628 630 630 632 632 634 637 11 Graphik 11.1 Allozieren von Farben . . . . . . . . 11.1.1 Farballozierung mit Methoden der Klasse QColor . 11.1.2 Farballozierung mit Methoden der Klasse QApplication 11.2 Grundlegendes zur Klasse QPainter . . . . . 11.2.1 Konstruktoren und Methoden der Klasse QPainter 11.2.2 Beispiele . . . . . . . . . 11.3 Einstellungen für QPainter-Objekte . . . . . 11.3.1 Einstellen des Zeichenstifts . . . . . . 11.3.2 Festlegen eines Füllmusters . . . . . . 11.3.3 Festlegen eines neuen Zeichenfonts . . . . 11.3.4 Beispiel: Zufällige Zeichenstifte mit allen Füllmustern 11.3.5 Übung: Interaktives Einstellen von Stift und Füllmuster 11.4 Positionieren und Ausgeben von Figuren und Text . . 11.4.1 Positionieren . . . . . . . . . 11.4.2 Zeichnen geometrischer Figuren . . . . . 11.4.3 Ausgeben von Text . . . . . . . 11.5 Alternatives Ausgeben von Figuren . . . . . 11.5.1 Funktionen aus <qdrawutil.h> . . . . 11.5.2 Beispielprogramm zu den Funktionen aus <qdrawutil.h> 11.5.3 Übung: Game of Life . . . . . . . 11.6 Transformationen . . . . . . . . . 11.6.1 Einfache World-Transformationen . . . . 11.6.2 World-Transformationen mit der Klasse QWMatrix . 11.6.3 View-Transformationen . . . . . . 11.7 Clipping . . . . . . . . . . . 11.7.1 Festlegen von Clipping-Regionen . . . . 11.7.2 Die Klasse QRegion . . . . . . . 11.7.3 Beispielprogramm zu Clipping . . . . . 11.7.4 Übung: Vorbeifliegende Gegenstände an Fensterwand 11.8 QPainter-Zustand sichern und wiederherstellen . . 11.8.1 Die QPainter-Methoden save() und restore() 11.8.2 Beispiel: Drehen einer sich ständig ändernden Figur 11.8.3 Übung: QPainter-Zustände im Stack . . . 11.9 Flimmerfreie Darstellung . . . . . . . 11.9.1 Ausschalten der Hintergrundfarbe . . . . 11.9.2 Vermeiden überflüssigen Zeichnens . . . . 639 639 640 641 642 643 643 650 650 650 652 652 655 657 657 657 660 670 670 671 674 675 675 688 691 708 708 708 709 711 712 712 712 716 716 717 718 XVII Inhaltsverzeichnis 11.9.3 Doppel-Pufferung . . . . 11.10Die QCanvas-Klassen . . . . . 11.10.1 Die Klasse QCanvas . . . . 11.10.2 Die Klasse QCanvasItem . . . 11.10.3 Die Klasse QCanvasLine . . . 11.10.4 Die Klasse QCanvasRectangle . 11.10.5 Die Klasse QCanvasEllipse . . 11.10.6 Die Klasse QCanvasPolygon . . 11.10.7 Die Klasse QCanvasPolygonalItem 11.10.8 Die Klasse QCanvasSprite . . 11.10.9 Die Klasse QCanvasText . . . 11.10.10Die Klasse QCanvasPixmap . . 11.10.11Die Klasse QCanvasPixmapArray . 11.10.12Die Klasse QCanvasView . . . 11.10.13Demoprogramm zu den QCanvas-Klassen 11.10.14Übung zu den QCanvas-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719 727 727 729 731 731 732 732 733 733 734 734 735 735 736 745 12 Bildformate und Cursorformen 12.1 Pixmap-Klassen . . . . . . . . . 12.1.1 Format einer Pixmap . . . . . . . 12.1.2 Die Klasse QPixmap . . . . . . . 12.1.3 Die Klasse QPixmapCache . . . . . . 12.1.4 Die Klasse QBitmap . . . . . . . 12.1.5 Beispiel: Erstellen eines Screenshot durch Ziehen der Maus 12.1.6 Übung: Screenshot vom Bildschirm oder eines Teilbereichs 12.2 Die Klasse QCursor . . . . . . . . 12.2.1 Konstruktoren und Methoden der Klasse QCursor . 12.2.2 Beispiel zu vor- und benutzerdefinierten Cursorformen 12.2.3 Übung: Ändern des Mauscursor bei einem Mausklick 12.3 Die Klassen QImage und QImageIO . . . . . 12.3.1 Konstruktoren und Methoden der Klasse QImage . 12.3.2 Routinen zum Setzen bzw. Erfragen einzelner Pixel . 12.3.3 Die Klasse QImageIO für benutzerdefinierte Bildformate 12.3.4 Beispiel: Einfache Bildbearbeitung . . . . 12.3.5 Übung: Erweiterte Bildbearbeitung . . . . 12.4 Die Klasse QPicture . . . . . . . . 12.4.1 Konstruktoren und Methoden der Klasse QPicture 12.4.2 Beispiel: Demoprogramm zur Klasse QPicture . 747 747 747 748 751 751 752 754 754 755 757 759 759 760 763 764 765 770 770 771 771 13 Animationen und Sounds 13.1 Animationen mit der Klasse QMovie . . . . . 13.1.1 Konstruktoren und Methoden der Klasse QMovie . 13.1.2 Beispiel: Abspielen von Filmen . . . . . 13.1.3 Beispiel: Einstellen der Abspielgeschwindigkeit . 13.1.4 Übung: Anzeigen einzelner Frames (Bilder) eines Films 13.2 Sound mit der Klasse QSound . . . . . . . 775 775 775 778 783 785 786 XVIII Inhaltsverzeichnis 13.2.1 Konstruktor und Methoden der Klasse QSound . 13.2.2 Beispiel: Demoprogramm zur Klasse QSound . . 13.2.3 Übung: Auswahl einer Sound-Datei über QFileDialog 14 Konsistente Eingaben und reguläre Ausdrücke 14.1 Konsistente Eingaben mit Klasse QValidator . . 14.1.1 Die Basisklasse QValidator . . . . 14.1.2 Die Klasse QIntValidator . . . . 14.1.3 Die Klasse QDoubleValidator . . . 14.2 Reguläre Ausdrücke (Klasse QRegExp) . . . . 14.2.1 Unterschiedliche Arten von regulären Ausdrücken 14.2.2 Escape-Sequenzen . . . . . . 14.2.3 Konstruktoren und Methoden der Klasse QRegExp 786 786 788 . . . . . . . . 789 790 790 794 796 799 800 801 802 15 Tastaturfokus 15.1 Einstellen und Erfragen von Fokusregeln . . . . 15.2 Reihenfolge beim Wechseln des Tastaturfokus mit der Tabtaste 813 813 817 16 Ereignisbehandlung (Event-Handling) 16.1 Allgemeines zu Events . . . . . . . . 16.2 Die Basisklasse QEvent und die davon abgeleiteten Event-Klassen 16.2.1 Die Basisklasse QEvent . . . . . . 16.2.2 Mal-Events (QPaintEvent) . . . . . 16.2.3 Maus-Events (QMouseEvent und QWheelEvent) . 16.2.4 Tastatur-Events (QKeyEvent) . . . . . 16.2.5 Timer-Events (QTimerEvent) . . . . . 16.2.6 Fokus-Events (QFocusEvent) . . . . . 16.2.7 Größenänderungs-Events (QResizeEvent) . . 16.2.8 Positionsänderungs-Events (QMoveEvent) . . 16.2.9 Eintritts- und Austritts-Events . . . . . 16.2.10 Versteck-, Sichtbarkeits- und Schließ-Events (QHideEvent, QShowEvent, QCloseEvent) . . . . . 16.2.11 Subwidget-Events (QChildEvent) . . . . 16.2.12 Drag-and-Drop-Events (QDragEnterEvent, QDragMoveEvent, QDragLeaveEvent, QDropEvent) . . 16.3 Event-Filter . . . . . . . . . . 16.4 Senden eigener Events . . . . . . . . 16.5 Benutzerdefinierte Events (QCustomEvent) . . . . 823 823 824 824 826 827 834 840 841 843 845 846 17 Signale und Slots 17.1 Verbindung zwischen einem Signal und einer Slotroutine . 17.2 Verbindung zwischen einem Signal und einem anderen Signal 17.3 Auflösen bzw. temporäres Ausschalten von bestehenden Signal-SlotVerbindungen . . . . . . . . . . 17.4 Verbinden mehrerer Buttons mit einer Slotroutine . . 17.5 Senden eigener Signale mit QSignal . . . . . 869 869 871 848 852 854 855 858 862 871 873 877 XIX Inhaltsverzeichnis 18 Erstellen eigener Widgets 18.1 Grundlegende Vorgehensweise beim Entwurf eigener Widgets 18.2 Beispiel: Implementieren eines Funktionsplotters . . . 18.2.1 Beschreibung des Funktionsplotters . . . . 18.2.2 Headerdatei für den Funktionsplotter . . . 18.2.3 Implementierung des Funktionsplotters . . . 18.2.4 Beispiel: Plotten einer Sinusfunktion . . . . 18.2.5 Beispiel: Plotten einer Funktion, die der Benutzer interaktiv eingibt . . . . . . . . . . 18.2.6 Übung: Plotten der Funktion 1-exp(0.5x) und deren Ableitung . . . . . . . . . . 18.3 Beispiel: Implementieren einer Bildertabelle . . . . 18.3.1 Beschreibung des Bildertabellen-Widget . . . 18.3.2 Headerdatei für das Bildertabellen-Widget . . 18.3.3 Implementierung das Bildertabellen-Widget . . 18.3.4 Beispiel: Ein Memory-Spiel . . . . . . 18.3.5 Beispiel: Ein Puzzle-Spiel . . . . . . 18.3.6 Beispiel: Ein Poker-Spiel . . . . . . 18.3.7 Übung: Ein Bilderbrowser für Dias . . . . 898 898 898 900 901 903 906 909 915 19 Thread-Programmierung und -Synchronisation 19.1 Die Klasse QThread . . . . . . 19.2 Synchronisation von Threads mit QMutex . . 19.3 Synchronisation von Threads mit QSemaphore . 19.4 Synchronisation von Threads mit QWaitCondition 19.5 Übung: Zuteilung von Plätzen in einem Speiseraum . . . . . . . . . . 917 917 922 927 937 942 20 Mehrsprachige Applikationen und Internationalisierung 20.1 Die Klasse QString für Unicode . . . . 20.2 Automatische Übersetzung in andere Sprachen . 20.3 Automatische Anpassung an lokale Besonderheiten 20.4 Konvertierung von Text-Kodierungen . . . 20.5 Übung: Landabhängiges Einblenden eines Datums . . . . . . . . . . 943 943 944 953 954 954 21 Test- und Debugging-Möglichkeiten 21.1 Testausgaben mit qDebug(), qWarning() und qFatal() 21.2 Die Makros ASSERT() und CHECK_PTR() . . . . 21.3 Debuggen mittels Objektnamen . . . . . . 21.4 Übung: Testausgaben in eine Log-Datei . . . . . 955 955 957 959 961 22 Netzwerkprogrammierung mit Qt 22.1 Protokollunabhängige Netzwerkprogrammierung 22.1.1 Die Klasse QUrlOperator . . . 22.1.2 Die Klasse QUrl . . . . . 22.1.3 Die Klasse QUrlInfo . . . . 22.1.4 Die Klasse QNetworkOperation . 965 965 965 974 976 978 XX . . . . . . . . . . . . . . 881 881 882 882 883 884 888 891 Inhaltsverzeichnis 22.1.5 Beispiel: Herunterladen einer Datei von einem FTP-Server mit Fortschrittsanzeige . . . . . . 22.1.6 Übung: Gleichzeitiges Herunterladen mehrerer Dateien mit Fortschrittsanzeigen . . . . . . . 22.2 Implementieren eigener Netzwerkprotokolle mit QNetworkProtocol . . . . . . . . . . . . 22.2.1 Vorgehensweise beim Implementieren eines eigenen Netzwerkprotokolls . . . . . . . . 22.2.2 Die Klasse QNetworkProtocol . . . . 22.2.3 Die Klasse QFtp . . . . . . . . 22.2.4 Die Klasse QLocalFs . . . . . . . 22.3 Socket-Programmierung . . . . . . . . 22.3.1 Die Klasse QSocket . . . . . . . 22.3.2 Die Klasse QSocketDevice . . . . . 22.3.3 Die Klasse QServerSocket . . . . . 22.3.4 Beispiel: Ein einfacher http-Dämon . . . . 22.3.5 Beispiel: Einfache Implementierung des nntp-Protokolls 22.4 Low-level Socket-Programmierung . . . . . 22.4.1 Die Klasse QSocketNotifier . . . . . 22.4.2 Die Klasse QHostAddress . . . . . . 22.4.3 DNS-Lookups mit der Klasse QDns . . . . 981 984 984 984 990 992 993 993 993 996 996 997 1000 1005 1005 1008 1009 23 Blockierungsfreie Datenübertragung im Hintergrund 1021 23.1 Die Klasse QDataSource . . . . . . . 1021 23.2 Die Klasse QDataSink . . . . . . . . 1022 23.3 Die Klasse QDataPump . . . . . . . . 1023 23.4 Beispiel: Demoprogramm zu den Klassen QDataSource, QDataSink und QDataPump . . . . . . . . 1023 23.5 Übung: Zählen der 0- und 1-Bits in Dateien . . . . 1025 24 Parsen von XML-Dokumenten 24.1 SAX2 und die zugehörigen Qt-Klassen . . . . . 24.1.1 Die SAX2-Schnittstelle von Qt . . . . . 24.1.2 Die Klassen der SAX2-Schnittstelle von Qt . . 24.1.3 Beispiel: Plotten einer Funktion über ein XML-Dokument 24.1.4 Beispiel: Anzeigen von XML-Dokumenten im Richtext-Format . . . . . . . . . . 24.2 DOM Level 1 und die zugehörigen Qt-Klassen . . . 24.2.1 Die DOM-Schnittstelle von Qt . . . . . 24.2.2 Die Klassen der DOM-Schnittstelle von Qt . . 24.2.3 Beispiel: Plotten einer Funktion über ein XML-Dokument 24.2.4 Beispiel:Anzeigen von XML-Dokumenten im Richtext-Format . . . . . . . . . . 24.3 Übung: Plotten einer Funktion als Linie oder in Balkenform über ein XML-Dokument . . . . . . . . . 1027 1027 1027 1032 1042 1048 1053 1053 1057 1072 1075 1077 XXI Inhaltsverzeichnis 25 Qt-Programmierung mit anderen Bibliotheken und Sprachen 25.1 OpenGL-Programmierung mit Qt . . . . . . 25.1.1 Die Klasse QGLWidget . . . . . . 25.1.2 Die Klasse QGLContext . . . . . . 25.1.3 Die Klasse QGLFormat . . . . . . 25.1.4 Beispiel: Drehen eines Quaders in x-, y- und z-Richtung 25.1.5 Übung: Drehen einer Pyramide in x-, y- und z-Richtung 25.2 Qt-Programmierung mit Perl . . . . . . . 25.2.1 Ein erstes einfaches PerlQt-Beispiel . . . . 25.2.2 Kurze Beschreibung von PerlQt . . . . . 25.2.3 Beispiele zur PerlQt-Programmierung . . . 25.3 Erstellen von Netscape Plugins . . . . . . 25.3.1 Herunterladen und Installieren des Plugin SDK . 25.3.2 Die Qt Netscape-Plugin Erweiterung . . . . 25.3.3 Kompilieren, Installieren und Testen von Plugins . 25.3.4 Beispiele für mit Qt erstellte Netscape Plugins . . 1079 1079 1080 1080 1081 1081 1084 1085 1085 1087 1092 1096 1096 1097 1102 1106 26 Der Qt GUI-Designer 26.1 Erstellen einer ersten einfachen Applikation mit dem Qt-Designer 26.2 Layout-Management im Qt-Designer . . . . . 26.3 Ändern der Tab Order . . . . . . . . 26.4 Weitere GUI-Builder . . . . . . . . 1117 1117 1131 1139 1142 27 Erstellen von Qt-Programmen mit KDevelop 1143 28 Das Tool tmake 28.1 Allgemeines zu tmake . . . 28.2 Installation von tmake . . . 28.3 Einfache Benutzung von tmake . 28.4 Konfiguration des Makefile . . 28.5 Variablen bei den einzelnen Templates 28.6 Setzen von Projektvariablen . . 28.7 Aufruf von tmake . . . . 28.8 Das Tool progen . . . . XXII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 1149 1149 1150 1151 1151 1152 1153 1154 Einleitung Ursachen erkennen, das eben ist Denken, und dadurch allein werden Empfindungen zu Erkenntnissen und gehen nicht verloren, sondern werden wesenhaft und beginnen auszustrahlen. – Herrmann Hesse Dieses Buch stellt die von der norwegischen Firma Trolltech entwickelte C ++-Klassenbibliothek Qt (Version 2.2) vor, die eine einfache und portable GUI-Programmierung ermöglicht. Mit Qt entwickelte Programme sind sofort ohne zusätzlichen Portierungsaufwand sowohl unter allen Unix- wie auch unter allen WindowsSystemen lauffähig. Sie müssen lediglich mit den entsprechenden Compilern (Visual C++ oder Borland C++ unter Windows-Systemen oder dem auf dem jeweiligen Unix-System angebotenen cc-Compiler) kompiliert und gelinkt werden. In Zukunft wird die Portabilität von entwickelter Software wohl immer wichtiger werden, denn warum sollte man ein Programm entwickeln, das nur unter WindowsSystemen lauffähig ist, und sich damit freiwillig aus dem Markt der Millionen von Unix- und Linux-Systemen ausschließen. Der umgekehrte Fall gilt selbstverständlich auch. Es stellt sich hier natürlich die Frage, warum man bei Neuentwicklungen nicht gleich die Programmiersprache Java verwenden sollte, die ebenfalls das Erstellen portabler Programme ermöglicht. Nun, Java hat sicherlich wie Qt den Vorteil der Portabilität, aber die Ablaufgeschwindigkeit von Java-Programmen kann nicht mit der von Qt-Programmen mithalten. Außerdem sollte man berücksichtigen, dass Qt eine C++-Bibliothek ist, und schon von Programmierern, die die Programmiersprache C beherrschen und nur grundlegende Kenntnisse in C++ besitzen, verwendet werden kann. Und die Anzahl von Softwareentwicklern mit diesem Profil ist sehr, sehr groß. Voraussetzungen des Lesers Ein gutes Beherrschen der Programmiersprache C wird in diesem Buch ebenso vorausgesetzt wie die Kenntnis der wesentlichen C-Standardfunktionen. Wie bei jedem fortgeschrittenen Programmierkurs kann auch hier ein Basiswissen über grundlegende Datenstrukturen und Algorithmen nur von Vorteil sein. 1 Einleitung Ein paar Worte zu diesem Buch Bei einer so mächtigen Bibliothek wie Qt mit Hunderten von Klassen und Tausenden von Methoden, die zum Teil an Subklassen weitervererbt werden, stellt sich natürlich die Frage, wie man so etwas vermitteln kann. Ein bloßes Vorstellen der Klassen mit ihren Methoden und Datentypen wäre wenig sinnvoll, da der Neuling zum einen von der Vielzahl der Informationen erschlagen würde und zum anderen nicht das Zusammenspiel der einzelnen Klassen, was wohl für die Praxis mit am wichtigsten ist, kennenlernen würde. Hier wurde daher folgende Vorgehensweise gewählt: ❏ Vorstellen der wesentlichen Konstrukte, Klassen und Methoden von Qt Es werden nicht alle Klassen, sondern nur die wesentlichen Klassen sowie dort nur die wichtigsten Methoden vorgestellt. So soll vermieden werden, dass der Leser sich durch die Vielzahl der Informationen überfordert fühlt. Eine vollständige Referenz zu Qt befindet sich in der bei der Qt-Software mitgelieferten Online-Dokumentation, ohne die auch erfahrene Qt-Programmierer kaum auskommen. ❏ Zusammenfassen der Klassen zu funktionalen Themengebieten Eine Beschreibung der Klassen in alphabetischer Reihenfolge würde dazu führen, dass der Leser die Klassen – ähnlich dem Lernen nach einem Lexikon – nur unstrukturiert kennenlernen würde. Um dies zu vermeiden, ist dieses Buch nach Themengebieten strukturiert, in denen jeweils die Klassen zusammengefasst sind, die artverwandt sind und Ähnliches leisten. Dieses didaktische Prinzip „Vom Problem (Aufgabenstellung) zur Lösung (Klasse)“ bringt zwei Vorteile mit sich: Zum einen wird der Leser in einer strukturierten Form an die mächtige Qt-Bibliothek herangeführt, und zum anderen ermöglicht dieser Aufbau ein schnelles Nachschlagen beim späteren praktischen Programmieren, wenn zu einer gewissen Aufgabenstellung entsprechende Informationen benötigt werden. ❏ Beispiele, Beispiele und noch mehr Beispiele Um das Zusammenspiel der einzelnen Klassen und Methoden aufzuzeigen, werden immer wieder Beispiele (über 250 Beispielprogramme mit etwa 30.000 Codezeilen) eingestreut, um typische Konstrukte oder Programmiertechniken aufzuzeigen, die es ermöglichen, später beim selbstständigen Programmieren in diesen Beispielprogrammen nachzuschlagen, wenn ähnliche Problemstellungen vorliegen. Es sei an dieser Stelle darauf hingewiesen, dass sich so bisweilen auch umfangreichere Programmlistings ergeben, die vielleicht zunächst etwas abschreckend wirken; aber praxisnahes Programmieren, das durch dieses Buch vermittelt werden soll, hat eben selten etwas mit „ZwanzigZeilern“ zu tun. Um diese Listings nicht allzu groß werden zu lassen, werden die Methoden oft inline definiert, was hoffentlich verziehen wird. ❏ Übungen am Ende der Kapitel Um den Leser seine in einem Kapitel erworbenen Kenntnisse selbst testen zu lassen, befinden sich am Ende nahezu jeden Kapitels Übungsprogramme, die teilweise sehr anspruchsvoll sind. Bei einigen dieser nahezu 100 Übungspro- 2 Einleitung gramme (mit über 10.000 Codezeilen) muss der Leser eventuell in der QtOnline-Dokumentation nachschlagen, um die Aufgabenstellungen zu lösen. Dies ist beabsichtigt, da man in der späteren Programmierpraxis auch selbstständig arbeiten muss und kaum ohne ein Nachschlagen in der Qt-OnlineDokumentation auskommen wird. Übersicht über dieses Buch Das Buch gliedert sich in folgende Teile: Kapitel 1 gibt eine kurze Einführung in die Welt der Objektorientierung und insbesondere in die wichtigsten Konzepte der objektorientierten Sprache C ++, da solche grundlegenden Kenntnisse für eine Programmierung mit der objektorientierten C++-Klassenbibliothek erforderlich sind. Leser, die mit der Objektorientierung und C++ vertraut sind, können dieses Kapitel übergehen und unmittelbar mit Kapitel 2 fortfahren. Kapitel 2 klärt zunächst einmal, was Qt überhaupt ist und welche Vorteile es aufweist, bevor der wichtige Qt-Begriff „Widget“ eingeführt wird. Die folgenden Absätze gehen dann kurz auf die bei Qt mitgelieferte Dokumentation ein, bevor abschließend auf die Generierung von Qt-Programmen mit make sowie mit dem eigens von den Qt-Entwicklern angebotenen Tool tmake zur automatischen Erstellung von Makefiles eingegangen wird. Kapitel 3 gibt dann anhand von Beispielen einen Überblick über die wesentlichen Konzepte und Konstrukte von Qt. Es zeigt zunächst den grundsätzlichen Aufbau eines Qt-Programms, bevor es das wichtige Signal-Slot-Konzept von Qt detaillierter vorstellt. Ebenso wird in diesem Kapitel die Klasse QString vorgestellt, welche eine Abstraktion zu Unicode-Text und zum String-Konzept im klassischen C ist. Ein eigener Abschnitt stellt dann die von Qt verwendeten Farbmodelle vor und klärt, was Farbgruppen sind und wie Farbpaletten für Widgets geändert werden können. Im letzten, etwas umfangreicheren Abschnitt dieses Kapitels wird schließlich ein kleines Malprogramm zum Zeichnen mit der Maus auf dem Bildschirm erstellt, das schrittweise immer mehr erweitert wird, indem Menüs und Laufbalken hinzugefügt werden. In seiner letzten Version ist es sogar möglich, die gemalten Bilder zu speichern und wieder neu zu laden. Kapitel 4 gibt einen Überblick über die wichtigsten von Qt angebotenen Widgets. Die einzelnen Widgets sind in diesem Kapitel nach Themengebieten organisiert, in denen jeweils die Klassen zusammengefasst sind, die artverwandt sind und Ähnliches leisten. Kapitel 5 zeigt die unterschiedlichen Möglichkeiten des Layout und der Zuordnung von Widgets, wie sie von Qt angeboten werden. Kapitel 6 beschreibt die von Qt vordefinierten Dialogfenster, die für typische Kommunikationen mit dem Benutzer, wie z. B. Auswahl einer bestimmten Farbe 3 Einleitung oder einer Datei, ausgelegt sind. Diese vordefinierten Dialogfenster nehmen dem Qt-Programmierer viel Arbeit ab, da sie schon mit entsprechenden Auswahlmöglichkeiten und/oder Buttons versehen sind. Kapitel 7 stellt dann die von Qt angebotenen Klassen für Datei- und VerzeichnisOperationen vor, die nicht nur plattformunabhängig, sondern auch einfach zu verwenden sind. Kapitel 8 stellt zunächst die von Qt vordefinierten Datentypen (Klassen) QPoint, QSize und QRect vor, die vor allen Dingen beim Zeichnen geometrischer Objekte in einer Malfläche benötigt werden. Bevor dieses Kapitel dann mit der detaillierteren Beschreibung der einzelnen von Qt angebotenen TemplateKlassen für typische Datenstrukturen wie z. B. Arrays oder Listen beginnt, stellt es zunächst nochmals kurz grundlegende Konzepte von C ++ vor, die für das Verständnis der nachfolgenden Abschnitte notwendig sind. Dabei werden zunächst Konzepte wie „explizites und implizites Sharing“ oder „tiefe Kopie“ (deep copy) und „flache Kopie“ (shallow copy) geklärt, bevor die entsprechenden Template-Klassen und Methoden aufgezählt werden, die das jeweilige Konzept verwenden. Kapitel 9 zeigt, wie unterschiedliche Applikationen direkt untereinander Daten unter Verwendung des global verfügbaren Clipboard bzw. mittels der Drag-andDrop-Technik austauschen können. Kapitel 10 stellt Klassen vor, mit denen man Datums- und Zeitoperationen durchführen oder sich aber auch Zeitschaltuhren (Timer) einrichten kann, die in festgelegten Zeitperioden immer wieder Signale an das eigene Programm schicken. Kapitel 11 stellt zunächst die Möglichkeiten der Farballozierung mit Qt vor, bevor es sich tiefergehend mit den mächtigen Grafik-Klassen von Qt beschäftigt, die alles zeichnen lassen, von einfachen Linien bis zu komplexen Figuren wie Kuchenstücke oder andere geometrische Figuren. Daneben zeigt dieses umfangreichere Kapitel, wie Grafiken mit Qt auch transformiert, z. B. vergrößert oder gedreht werden können. Ein eigenes Unterkapitel stellt dann noch einige Techniken vor, mit denen man Flimmern beim Neuzeichnen eines Bildes vermeiden oder zumindest reduzieren kann. Der letzte Abschnitt stellt schließlich noch die QCanvas-Klassen vor, mit denen Qt einen weiteren Satz von Klassen für zweidimensionale Grafiken zur Verfügung stellt. Diese erlauben es, grafische Elemente schneller zeichnen zu lassen, und sie benötigen auch wenig Speicher. Neben weiteren Vorteilen erlauben diese Klassen auch mehrere Ansichten der gleichen Grafikfläche. Kapitel 12 stellt die von Qt unterstützen Bildformate und Cursorformen vor. Dazu geht es zunächst auf die Pixmap-Klassen ein, die für Zeichnungen ausgelegt und optimiert sind. Im nächsten Abschnitt wird dann die Klasse QCursor behandelt, mit der man dem Mauscursor ein spezielles Aussehen geben kann. Der dritte Abschnitt stellt mit der Klasse QImage die zweite Klasse neben 4 Einleitung den Pixmap-Klassen vor, die von Qt für die Bildbearbeitung angeboten wird. Während die Pixmap-Klassen für Zeichnungen ausgelegt und optimiert sind, ist die Klasse QImage für E/A, direkte Pixel-Zugriffe und -Manipulationen geeignet, da sie ein hardwareunabhängiges Pixmap-Format verwendet. Im letzten Abschnitt dieses Kapitels wird noch die Klasse QPicture vorgestellt, die es ermöglicht, Mal-Kommandos aufzuzeichnen und später wieder ausführen zu lassen. Kapitel 13 geht auf Animationen und Sounds ein und zeigt, wie man mit den eigenen von Qt angebotenen Klassen animierte Bilder oder eben Sound-Dateien abspielen kann. Kapitel 14 zeigt zunächst, wie man falsche Benutzereingaben verhindern kann, bevor es die von Qt unterstützten regulären Ausdrücke vorstellt. Kapitel 15 behandelt den Tastaturfokus, der immer nur auf ein Eingabeelement eingestellt sein kann. Den Tastaturfokus besitzt immer das Eingabeelement, das gerade Eingaben von der Tastatur entgegennehmen kann. Der Tastatur Tab -Taste auf das nächste Eingabeelement fokus kann üblicherweise mit der Tab -Taste bei gleichzeitig gedrückter Shift -Taste auf das vorbzw. mit der herige Eingabeelement verschoben werden. Ebenso kann man üblicherweise den Tastaturfokus direkt auf ein Eingabeelement einstellen, indem man auf dieses mit der Maustaste klickt. Kapitel 16 erläutert zunächst einmal die grundsätzliche Vorgehensweise von Qt beim Auftreten von Events, bevor es im nächsten Abschnitt die Basisklasse QEvent und alle von ihr abgeleiteten Event-Klassen vorstellt. Der nächste Abschnitt behandelt dann so genannte „Event-Filter“. Ein Event-Filter ist ein Objekt, das alle Events für andere Objekte empfängt. Dieses Objekt kann dann entscheiden, ob es auf die empfangenen Events selbst reagiert und/oder die empfangenen Events an die entsprechenden anderen Objekte weiterleitet oder nicht. In den beiden letzten Abschnitten dieses Kapitels wird dann das Senden eigener Events und die Bearbeitung benutzerdefinierter Events vorgestellt. Kapitel 17 stellt das „Signal-Slot-Konzept“, das zwar bereits zu Beginn kurz beschrieben und in den Beispielen der vorherigen Kapitel auch ständig verwendet wurde, nochmals vollständig vor, wobei es auch einige bisher noch nicht behandelte Aspekte des Signal-Slot-Konzepts zeigt. Kapitel 18 zeigt, wie man sich eigene Widget-Klassen erstellen kann. Dazu stellt dieses Kapitel zunächst einige wichtige Punkte vor, die dabei zu beachten sind, bevor es anhand von zwei umfangreicheren Beispielen (Funktionsplotter und Tabelle von Bildern) das Erstellen eigener Widgets verdeutlicht. Kapitel 19 stellt zunächst die von Qt angebotene plattformunabhängige ThreadProgrammierung und -Synchronisation vor. Dazu stellt es zunächst die für Threads zu verwendende Klasse QThread vor, bevor es Klassen vorstellt, mit denen gleichzeitige laufende Threads synchronisiert werden können. 5 Einleitung Kapitel 20 zeigt, wie man mehrsprachige und international verwendbare Qt-Programme erstellen kann. So entwickelte Qt-Applikationen lassen sich leicht und ohne viel Aufwand an länder- und kulturspezifische Gegebenheiten anpassen, so dass der Benutzer dieser Applikation entsprechend seinen Gewohnheiten die entsprechende Sprache, Zeichenkodierung und -darstellung verwenden kann. Kapitel 21 stellt zum einen Funktionen und Makros vor, mit denen man in einem Programm Testausgaben und automatische Verifizierungen einbauen kann. Zum anderen zeigt es, wie man Qt-Objekte mit Namen versehen kann, um sich dann beim Programmablauf mittels eigens dafür konzipierten Qt-Funktionen Debug-Informationen ausgeben zu lassen. Kapitel 22 stellt die drei unterschiedlichen Typen von Klassen vor, mit denen man leicht und portabel Netzwerkprogrammierung durchführen kann. Der erste Typ von Netzwerk-Klassen, der in diesem Kapitel vorgestellt wird, ist eher passiver Art. Zu dieser Art gehören unter anderem die beiden Klassen QUrl und QUrlOperator, mit denen man URLs (Uniform Resource Locator) protokollunabhängig bearbeiten kann. Danach stellt dieses Kapitel die Klasse QNetworkProtocol vor, die eine abstrakte Ebene zur Verfügung stellt, auf der man eigene Netzwerkprotokolle implementieren kann. Die Klasse QUrlOperator ermöglicht dann ein Arbeiten mit solchen selbstdefinierten Netzwerkprotokollen. Im letzten Teil dieses Kapitels wird dann auf Klassen wie QSocket, QServerSocket, QDns, QFtp usw. eingegangen, die ein portables Arbeiten mit TCP/IP-Sockets ermöglichen. Kapitel 23 zeigt, wie man blockierungsfrei Daten im Hintergrund übertragen kann, denn das Schreiben in oder das Lesen aus Dateien kann bei großen Datenmengen eine sehr zeitaufwendige Operation sein, in der das ganze Programm blockiert ist, so dass der Benutzer in dieser Zeit nicht weiter mit der Applikation arbeiten kann. Qt bietet für solche Situationen abstrakte Klassen, die eine Übertragung von Daten im Hintergrund durchführen lassen. Diese Klassen werden in diesem Kapitel beschrieben. Kapitel 24 behandelt das XML-Modul von Qt, das einen XML-Parser mit einer SAX2- (Simple API for XML) Schnittstelle und eine Implementierung des DOM Level 1 (Document Object Model) zur Verfügung stellt. SAX2 ist eine sehr beliebte Java-Schnittstelle für XML-Parser, und DOM Level 1 ist eine W3CEmpfehlung für XML-Schnittstellen. Kapitel 25 stellt von der Vielzahl der zwischenzeitlich entwickelten Qt-Schnittstellen zu anderen Bibliotheken und Sprachen drei der wichtigsten kurz vor: OpenGL-Programmierung mit Qt, Perl-Programmierung mit Qt und Erstellen von Netscape-Plugins mit Qt. Kapitel 26 stellt den Qt GUI-Designer vor, der ein visuelles Design-Tool ist, das das Entwerfen und Implementieren grafischer Benutzerschnittstellen erheblich vereinfacht. Dieses Kapitel gibt anhand von Beispielen eine kurze Einführung in den bei Qt mitgelieferten Qt-Designer. 6 Einleitung Kapitel 27 stellt die im Rahmen des KDE-Projekts1 entwickelte Entwicklungsumgebung KDevelop kurz vor. KDevelop erleichtert das Erstellen von GUI-Programmen ganz wesentlich und spart Zeit durch Automatisierung von StandardEntwicklungsprozessen, genauso wie es einen direkten und transparenten Zugriff auf alle Informationen bietet, die man benötigt. Kapitel 28 beschreibt das von der Firma Trolltech bereitgestellte Tool tmake, mit dem man sich automatisch Makefiles aus seinen Qt-Quellprogrammen generieren lassen kann. Beispiel- und Übungsprogramme auf der CD Alle Programmbeispiele und Übungsprogramme dieses Buches befinden sich auf der in diesem Buch enthaltenen CD. Für Linux/Unix existiert auch ein eigener Browser, um alle Programmlistings interaktiv zu lesen bzw. diese Programme auch über diesen Browser zu starten; siehe dazu auch Abbildung 1. Um diesen Browser zu starten, müssen Sie nur in das Directory wechseln, in dem Sie die CD gemountet haben und dann qtbuch aufrufen. Noch ein kurzer Hinweis: Sollte Sie der tanzende Pinguin stören, bewegen Sie den Mauscursor auf ihn und warten Sie ein wenig, bis ein Tooltip eingeblendet wird. Das Lizenzmodell von Trolltech Trolltechs Lizenzmodell ist eigentlich relativ einfach, auch wenn es immer wieder für Verwirrung sorgt. In erster Linie ist Qt als kommerzielle Software erhältlich, derzeit für die drei Plattformen Unix/X11, MS-Windows und Linux/Embedded. An Unterstützung für weitere Plattformen – z.B. Mac OS X – wird gearbeitet. Als kommerzieller Lizenznehmer der Desktop-Verion von Qt erhalten Sie ❏ die Qt-Bibliothek mit vollständigem Quellcode ❏ eine persönliche Lizenz um kommerzielle Anwendungen mit Qt entwickeln zu können ❏ ein Jahr freie Upgrades auf alle neuen Versionen von Qt ❏ ein Jahr E-Mail-Support ❏ die vollständige Referenz Dokumentation Es gibt keine Royalties, Run-Time-Lizenzen oder weitere Kosten, d. h. Sie können ohne weiteres Qt-basierte Anwendungen statisch oder dynamisch gelinked vertreiben. Derzeit werden zwei verschiedene Editionen angeboten: ❏ die Professional Edition und die ❏ Enterprise Edition 1 KDE ist die Abkürzung für „K Desktop Environment“ (siehe auch http://www.kde.org). 7 Einleitung Abbildung 1: Der Browser für die Beispiel- und Übungsprogramme (unter Linux/Unix) Unterschiede liegen im Umfang und Preis. Als Preisbeispiel kostet die Dual-Pack Enterprise Edition für 6 Entwickler für sowohl MS-Windows als auch Unix/X11 pro Entwickler 2 490 USD (Stand Juni 2001). Im Preis enthalten sind ein Jahr Upgrades und technischen Support. Mit dieser Preisstruktur befindet sich Trolltech deutlich im unteren Preissegement bei C/cppMultiplattform-Lösungen, aber eben auch über dem gewöhnlichen Budget von Privatanwendern oder Studenten. Fuer Universitäten hat Trolltech deshalb das Qt Educational Program ins Leben gerufen, dass es ermöglicht, für Ausbildungszwecke kostenlose Site-Lizenzen für Qt zu erwerben. Privatleute haben die Möglichkeit, kostenlos die Qt NonCommercial Edition auszuprobieren und damit geschriebene Programme als freie Software zu vertreiben. Und last but not least: Für Benutzer Freier bzw. Open-Source Betriebsysteme wie Linux oder FreeBSD, die Freie bzw. Open-Source Software mit Qt schreiben wollen, gibt es die Qt Free Edition, die unter den Open-Source Lizenzen QPL und GNU GPL vertrieben wird. Freie bzw. Open-Source Software bedeutet nicht nur, dass diese Software in der Regel umsonst ist. Alle Anwender der Software müssen den 8 Einleitung komplette Quellcode umsonst bekommen können, einschliesslich des Rechts, die Software verändert oder unverändert weitervertreiben zu dürfen. Wichtig: Wenn Sie kommerzielle bzw. proprietäre Software mit Qt entwickeln – auch unter Linux – brauchen sie eine kommerzielle Qt Lizenz. Im Zweifelsfall fragen Sie am besten einfach [email protected]. 9 Einleitung 10 Kapitel 1 Einführung in die Objektorientierung und C++ Kunst ist die rechte Hand der Natur. Diese hat nur Geschöpfe, jene hat Menschen gemacht. – F. Schiller Da Qt eine objektorientierte C++-Klassenbibliothek ist, wird hier eine kurze Einführung in die Welt der Objektorientierung und insbesondere in die wichtigsten Konzepte der objektorientierten Sprache C++ gegeben. Leser, die mit der Objektorientierung und C++ vertraut sind, können dieses Kapitel übergehen und unmittelbar mit Kapitel 2 fortfahren. Zunächst zeigt dieses Kapitel, dass auch die Natur, in der wir leben, objektorientiert ist, bevor es die wesentlichen Aspekte vorstellt, welche die objektorientierte von der traditionellen (funktionalen) Softwareentwicklung unterscheiden. Da C ++ eine Erweiterung der weitverbreiteten prozeduralen Sprache C ist, werden anschließend die Erweiterungen von C++ vorgestellt, die zwar sehr nützlich sind und ein eleganteres Programmieren in C zulassen, aber C++ noch nicht zu einer objektorientierten Sprache befähigen. Abschließend werden dann die wesentlichen neuen Sprachelemente vorgestellt, die C++ zu einer objektorientierten Sprache machen. 1.1 Objektorientierung in der realen Welt In der Welt, in der wir leben, sind wir von unzähligen Dingen (Objekten) mit verschiedenen Eigenschaften umgeben. Aufgrund dieser Eigenschaften sowie der Möglichkeiten, mit diesen Eigenschaften umzugehen oder von ihnen beeinflusst zu werden, kann man unterschiedliche Objekte zu Klassen zusammenfassen. Ein sehr schönes Beispiel hierfür liefert uns die Natur. Betrachten wir einen Ausschnitt aus der Welt der Lebewesen. Der Begriff „Lebewesen“ beschreibt umfassend alle möglichen (uns bekannten) Lebensformen auf unserem Planeten. Dahinter verbergen sich jedoch verschiedene Gruppen. So unterscheidet man z. B. „Pflanze“ und „Tier“. Diese Gruppen (Unter- 11 1 Einführung in die Objektorientierung und C++ L e b e w e s e n P fla n z e B a u m T ie r S ä u g e tie r B lu m e M e n s c h F is c h K a tz e H a u s k a tz e T ig e r Abbildung 1.1: Einteilung von Lebewesen klassen) kann man aufgrund unterschiedlicher Eigenschaften wiederum unterteilen (Tier: „Säugetier“, „Fisch“ etc.). Es sind dann weitere Differenzierungen möglich (Säugetier: „Mensch“, „Katze“ etc.), wobei auch diese Spezialisierungen weitere Unterteilungen zulassen, wie in Abbildung 1.1 gezeigt ist. Ordnet man jedem dieser Kästen aus Abbildung 1.1 bestimmte Eigenschaften zu, so erkennt man, dass die Anzahl der Eigenschaften von oben nach unten zunimmt. Der obersten Klasse („Lebewesen“) kann man nur die Eigenschaft „lebendig“ zuordnen. Gehen wir eine Stufe tiefer und betrachten die Gruppe „Tier“, die wieder alle gewisse Eigenschaften – wie z. B. „bewegungsfähig“ – gemeinsam haben, während die Gruppe „Pflanzen“ andere Charakteristika aufweist. Entscheidend ist, dass beide Gruppen, sowohl „Tiere“ als auch „Pflanzen“, die Eigenschaft „lebendig“ von der ihr übergeordneten Klasse „Lebewesen“ erben. Begeben wir uns noch weiter nach unten, so werden wir auf immer mehr (neue) Eigenschaften stoßen. Die Besonderheit liegt darin, dass eine Unterklasse sämtliche Eigenschaften der übergeordneten Klasse übernimmt (erbt). So ist letztendlich die genaue Beschreibung eines bestimmten Lebewesens möglich. Solange wir nur die Beschreibung eines bestimmten Lebewesens betrachten, sprechen wir also von Klasse. Nun gibt es aber von jeder möglichen untergeordneten Lebewesen-Klasse mehr oder weniger viele Vertreter (Exemplare). Hier sprechen wir dann von einem Objekt (auch als Instanz bezeichnet), das alle Eigenschaften der entsprechenden Klasse besitzt. So ist z. B. ein Tiger namens „Saimura“ in einem bestimmten Zoo ein Objekt (eine Instanz) der Klasse „Tiger“, die von der Klasse „Katze“ abgeleitet wurde, welche wiederum „Säugetier“ als Basisklasse hat usw. Allgemein gilt also, dass die in der realen Welt vorkommenden Elemente immer spezifischere Eigenschaften aufweisen, je tiefer sie sich in einer entsprechenden 12 1.1 Objektorientierung in der realen Welt Abbildung 1.2: Objekte (Exemplare) zur Klasse Tiger Baumhierarchie (wie sie z. B. in Abbildung 1.1 gezeigt) befinden. Bei gleichartigen Objekten wird also nicht jedes einzelne Objekt für sich beschrieben, sondern es wird eine allgemeine Beschreibung (Klasse) für diesen Typ von Objekten gegeben. Mit Hilfe solcher Beschreibungen lassen sich dann die konkreten Objekte den jeweiligen Klassen zuordnen. Jedes individuelle Objekt ist dann ein Exemplar der entsprechenden Klasse (siehe auch Abbildung 1.2). Die Tiger „Samurai“, „Taigon“ und „Rufus“ in Abbildung 1.2 sind alle Exemplare (Instanzen, Objekte) der Klasse „Tiger“. Es ist offensichtlich, dass die Klasse „Tiger“ kein eigenes Objekt ist, sondern eben nur eine Beschreibung. In den nachfolgenden Abbildungen werden Klassen und Objekte nach der Notation der Unified Modeling Language (UML) dargestellt, d. h. als Rechtecke. Zur Unterscheidung von Klassen und Objekten wird bei Objekten der Name unterstrichen: O b je k t K la s s e Abbildung 1.3: Objekt und Klasse in der UML-Notation Wenn man die Objekt-Klassen-Beziehung (Exemplarbeziehung, Instanzbeziehung) darstellen möchte, wird zwischen einem Objekt und seiner Klasse ein gestrichelter Pfeil in Richtung der Klasse gezeichnet: K la s s e < in s ta n c e o f> O b je k t Abbildung 1.4: Objekt-Klassen-Beziehung Im Falle des Tigers „Samurai“ sagt man dann: „Samurai ist ein Exemplar der Klasse Tiger“ oder „Samurai ist eine Instanz der Klasse Tiger“: 13 1 Einführung in die Objektorientierung und C++ < in s ta n c e o f> T ig e r S a m u ra i Abbildung 1.5: Beispiel einer Objekt-Klassen-Beziehung Die Objektorientierte Programmierung (OOP) stützt sich auf diese Denkweise. Es besteht die Möglichkeit, Klassen zu definieren und ihre Eigenschaften an Unterklassen zu vererben, um letztendlich die genaue Beschreibung eines bestimmten Sachverhalts zu erreichen. Ausgehend von dieser nun erhaltenen Beschreibung, können Objekte (Instanzvariable) deklariert/definiert werden, die letztendlich eine greifbare Repräsentation der jeweiligen Beschreibung darstellen. 1.2 Objektorientierung in der Software In diesem Kapitel werden die wesentlichen Konzepte vorgestellt, welche die objektorientierte Softwareentwicklung von der traditionellen (funktionalen) Softwareentwicklung unterscheiden. Schritt 1: Zusammenfügen von Daten und Funktionen Der erste Schritt zur Übernahme der Objektorientierung in die Softwareentwicklung war, dass man Daten und Funktionen, die in der funktionalen Softwareentwicklung noch als getrennte Einheiten nebeneinander standen, zu einer Einheit zusammenfügte, wie dies Abbildung 1.6 verdeutlicht. Hierbei lag die Idee des „Füge zusammen, was zusammengehört“ zugrunde. Man beseitigte damit einen ersten großen Nachteil von nicht objektorientierten Programmen, die keinen direkten Bezug zwischen Daten und den Funktionen, die auf diese Daten lesend oder schreibend zugriffen, direkt erkennen ließen. Wie leicht aus Abbildung 1.6 zu erkennen ist, verschmelzen bei der Objektorientierten Programmierung die Daten und die (diese Daten bearbeitenden) Funktionen zu einer Einheit, wodurch eine klare, eindeutige und überschaubare Softwarestruktur K la s s is c h e ( fu n k tio n a le ) S o ftw a r e e n tw ic k lu n g D a te n D a te n V a r ia b le x F u n k tio n 1 O b je k to r ie n tie r te S o ftw a r e e n tw ic k lu n g V a r ia b le y F u n k tio n 2 F u n k tio n 3 V a r ia b le 1 V a r ia b le b V a r ia b le 2 F u n k tio n x V a r ia b le 3 F u n k tio n y F u n k tio n i F u n k tio n z F u n k tio n x Abbildung 1.6: Klassische und objektorientierte Programmierung 14 D a te n V a r ia b le a 1.2 Objektorientierung in der Software K la s s is c h e ( fu n k tio n a le ) S o ftw a r e e n tw ic k lu n g D a t e n ( n a c h a u ß e n h in g e s c h ü tz t) D a te n V a r ia b le a V a r ia b le x U n k o n tr o llie r te r Z u g r iff m ö g lic h F u n k tio n 1 O b je k to r ie n tie r te S o ftw a r e e n tw ic k lu n g F r e m d fu n k tio n V a r ia b le b U n k o n tr o llie r te r Z u g r iff n ic h t m ö g lic h F u n k tio n x F r e m d fu n k tio n F u n k tio n y F u n k tio n z Abbildung 1.7: Zugriffsschutz bei der Objektorientierten Programmierung erreicht wird. Es lässt sich auf einen Blick erkennen, welche Daten durch welche Funktionen bearbeitet (verändert) werden. Schritt 2: Information Hiding Ein zweiter großer Nachteil der klassischen funktionalen Programmierung ist ihr mangelndes Schutzkonzept, da sie einen ungeschützten (meist auch ungewollten) Zugriff „fremder“ Funktionen auf Daten zulässt. Um diesen Nachteil zu beseitigen, woraus oft schwer auffindbare Fehler resultierten, führte die Objektorientierung ihr eigenes Schutzkonzept ein, indem sie Möglichkeiten anbietet, Daten und Funktionen einer Klasse verschiedenen Schutzgraden (privat: nur innerhalb der Klasse ansprechbar; öffentlich: auch außerhalb der Klasse zugänglich) zuzuordnen. So können bei entsprechender Definition die Daten einer Klasse nur über die vom Programmierer zur Verfügung gestellten Funktionen verändert werden. Ein unkontrollierter Zugriff durch Fremdfunktionen wird somit verhindert. Abbildung 1.7 verdeutlicht diesen Sachverhalt. Diese Abbildung zeigt auch, dass ein Zugriff auf die geschützten Daten niemals direkt, sondern nur durch die nach außen sichtbaren Funktionen möglich ist. Schritt 3: Verwendung bereits vorhandener Software Wie bereits angesprochen, werden in der Objektorientierten Programmierung Objekte aufgrund vorliegender Klassendefinitionen gebildet. Somit besteht die Möglichkeit, Klassendefinitionen für oft benötigte Sachverhalte in so genannten „Klassenbibliotheken“ zu hinterlegen. Durch einfaches Übernehmen dieser Definitionen (und eventuelles Hinzufügen neuer Teile mit Hilfe des Vererbungsmechanismus) wird die Softwareentwicklung stark vereinfacht. Man spricht auch von Softwareentwicklung durch Reproduktion (Nachbildung) von Objektbeschreibungen (Klassendefinitionen). 15 1 Einführung in die Objektorientierung und C++ 1.3 Nicht-objektorientierte Erweiterungen in C++ Da C++ eine Erweiterung der weitverbreiteten prozeduralen Sprache C ist, werden hier zunächst die Erweiterungen von C++ vorgestellt. 1.3.1 Zeilen-Kommentare mit // Neben dem C-Kommentar, der innerhalb des Codes mit der Zeichenfolge /* eingeleitet und mit der Zeichenfolge */ beendet wird, bietet C++ zusätzlich noch die Zeichenfolge // zum Kommentieren an: Alle Zeichen ab // bis zum Zeilenende werden als Kommentar interpretiert. double epsilon; /* C-Kommentar, der sich über meherere Zeilen erstrecken kann und auch in C++ weiterhin verwendet werden kann. */ double epsilon; // Ab hier bis Zeilenende Kommentar (nur in C++ mögl.) 1.3.2 Variablen-Deklarationen (auch im Anweisungsteil) In C war es vorgeschrieben, dass Variable nur entweder global oder am Anfang eines durch { } gekennzeichneten Blockes deklariert werden durften. VariablenDeklarationen an beliebigen Stellen innerhalb des Anweisungsteils waren nicht erlaubt. In C++ können nun Variablen-Deklarationen an jeder beliebigen Stelle im Code erfolgen. Die Lebensdauer der deklarierten Variablen beschränkt sich dabei (wie auch in C) auf den Block, in dem sie deklariert wurden: void function() { ........ // ...... printf("C-Anweisungen"); // beliebige C/C++-Anweisungen ........ // ...... int z = 5; // Deklaration der Variablen ’z’ // Diese Variable ist nur innerhalb der ......... // Funktion function() bekannt } int main(void) { ........ // ...... printf ("C-Anweisungen"); // beliebige C/C++-Anweisung ........ // ...... for (int i = 1; i < 10; i++) { ...... } return 0; } 16 // Deklaration der Variablen ’i’ // Diese Variable ist innerhalb // der Funktion main bekannt 1.3 Nicht-objektorientierte Erweiterungen in C++ 1.3.3 Default-Argumente bei Funktionsaufrufen Es gibt Anwendungsfälle, bei denen nicht alle bei einer Funktionsdeklaration angegebenen Parameter bei jedem Aufruf wirklich benötigt werden. In solchen Fällen muss man in C beim Aufruf trotzdem für jeden Parameter ein entsprechendes Argument (Dummy-Argument) angeben. Nehmen wir z. B. eine Funktion add_bis4(), die bis zu vier ganze Zahlen (als Argumente anzugeben) addieren kann und das Ergebnis zurückgibt. int add_bis4(int z1, int z2, int z3, int z4) { return(z1+z2+z3+z4); } Will man in C nun nur zwei Zahlen durch diese Funktion addieren lassen, muss man trotzdem alle vier Argumente angeben: ergeb = add_bis4(25, 43, 0, 0); /* in C: Dummy-Argumente 0, 0 */ C++ bietet nun für solche Fälle so genannte Default-Argumente an, die man den Parametern bei der Deklaration/Implementierung einer Funktion zuweisen kann, wie z. B.: int add_bis4(int z1, int z2=0, int z3=0, int z4=0) { return(z1+z2+z3+z4); } Gibt der Aufrufer der Funktion das jeweilige Default-Argument nicht an, so wird dieses Argument automatisch mit seinem Default-Wert belegt: ergeb = add_bis4(25, 43); // entspr.: ergeb = add_bis4(25, 43, 0, 0); ergeb = add_bis4(7, 4, -8); // entspr.: ergeb = add_bis4(7, 4, -8, 0); ergeb = add_bis4(53); // entspr.: ergeb = add_bis4(53, 0, 0, 0); Default-Argumente werden oft auch dazu verwendet, um für eine Funktion ein bestimmtes Standardverhalten vorzugeben. Werden beim Aufruf dieser Funktion keine Argumente für die optionalen Default-Argumente angegeben, so verhält sich die Funktion entsprechend ihrem festgelegten Standard. Möchte der Aufrufer aber die Funktion abweichend von ihrer Standardvorgabe ausführen lassen, kann er dies über die Angabe eigener Argumente (für die Default-Argumente) steuern. Nachfolgend ist hierzu ein Beispiel gegeben. void kostrech(double einnahme, double ausgabe, char *waehrung="EUR", double factor=1.0) { double gewinn = einnahme - ausgabe; printf("Einnahme: %.2f %s (%.2f EUR)\n", einnahme, waehrung, einnahme*factor); printf("Ausgabe : %.2f %s (%.2f EUR)\n", ausgabe, waehrung, ausgabe*factor); printf("------------------------------------\n"); printf("Gewinn : %.2f %s (%.2f EUR)\n", gewinn, waehrung, gewinn*factor); } Für diese Funktion sind nun z. B. folgende Aufrufe möglich: 17 1 Einführung in die Objektorientierung und C++ kostrech(1370.34, 1250.76); // Standardverhalten // Ausgabe bei diesem Aufruf: Einnahme: 1370.34 EUR (1370.34 EUR) // Ausgabe : 1250.76 EUR (1250.76 EUR) // ------------------------------------ // Gewinn : 119.58 EUR (119.58 EUR) kostrech(1800.0, 2500.0, "YEN", 0.0095); // Ausgabe bei diesem Aufruf: Einnahme: 1800.00 YEN (17.10 EUR) // Ausgabe : 2500.00 YEN (23.75 EUR) // ------------------------------------ // Gewinn : -700.00 YEN (-6.65 EUR) kostrech(23487.40, 21345.7, "USD", 1.02); // Ausgabe bei diesem Aufruf: Einnahme: 23487.40 USD (23957.15 EUR) // Ausgabe : 21345.70 USD (21772.61 EUR) // // -----------------------------------Gewinn : 2141.70 USD (2184.53 EUR) Es ist zu beachten, dass Default-Argumente immer nur für die „hinteren“ (am weitesten rechts stehenden) Parameter innerhalb der Schnittstelle erlaubt sind. Würde beim Aufruf einer Funktion mit Default-Argumenten ein mittleres Argument weggelassen werden, wäre es dem Compiler nicht möglich herauszufinden, welcher Parameter entfallen ist. Demzufolge könnte er auch die nachfolgenden Argumente nicht richtig zuordnen. Dazu folgendes Beispiel: void f1(int a, int b, int c = 0); // erlaubt void f2(int a, int b = 0, int c = 0); // erlaubt void f3(int a, int b = 0, int c); // NICHT erlaubt Im Folgenden sind alle möglichen Aufrufformen dieser hier deklarierten Funktionen gezeigt: f1( 1, 2, 3); // Alle Argumente angegeben f1( 1, 2); // 3. Default-Argument weggelassen f2( 4, 5, 6); // Alle Argumente angegeben f2( 4, 5); // 3. Default-Argument weggelassen f2( 4); // 2. Und 3. Default-Argument weggelassen // f3() - Aufruf nicht möglich, da Definition syntaktisch falsch Default-Argumente dürfen nur im Prototyp, nicht aber bei der Definition einer Funktion angegeben werden. 1.3.4 Überladen von Funktionen Es besteht oft der Wunsch, für ähnliche, aber doch unterschiedliche Aufgaben Funktionsaufrufe mit gleichem Namen verwenden zu können. Anwendungsfälle und mögliche Lösungen hierfür wurden bereits im vorigen Kapitel vorgestellt. Es gibt aber auch Anforderungen, die sich durch Default-Argumente nicht lösen lassen. Zum Beispiel könnte man eine Funktion add() benötigen, die Variablenwerte un- 18 1.3 Nicht-objektorientierte Erweiterungen in C++ terschiedlichen Datentyps addiert. In C waren hierfür immer Funktionen mit verschiedenen Namen notwendig: void add_i(int i1, int i2); void add_d(double d1, double d2); // Addiert zwei Integers // Addiert zwei Doubles void add_il(int i1, int i2, long l1); ... // Addiert zwei Integers und ein long C++ bietet nun die Möglichkeit, mehrere Funktionen mit gleichem Namen, aber unterschiedlichen Schnittstellen zu implementieren. Man spricht dabei vom Überladen (Overloading) von Funktionen. Die Entscheidung, welche Funktion bei einem Aufruf ausgeführt wird, ist abhängig von der Anzahl und vom Datentyp der Argumente, da C++ intern zur Benennung einer Funktion nicht nur deren Namen, sondern auch die Anzahl und die Typen der Parameter verwendet. Programm 1.1 ist ein Beispiel zum Überladen von Funktionen, indem es die Funktion hoch() zum Berechnen von xy in drei Varianten anbietet. Programm 1.1 – overload.cpp: Überladen einer Funktion zur Berechnung von xy #include <stdio.h> #include <math.h> long hoch(int y, int x) { return (long)pow(x, y); long hoch(int y) { return (long)pow(10, y); } double hoch(int y, double x) { return pow(x, y); } } int main(void) { printf(" 3^4 = %ld\n", hoch(4, 3)); printf(" 10^5 = %ld\n", hoch(5)); printf("2.3^4 = %f\n", hoch(4, 2.3)); return 0; } Je nachdem, ob die Funktion hoch() mit zwei int-Argumenten, einem int-Argument oder aber einem int- und einem double-Argument aufgerufen wird, wird die entsprechende Funktion aufgerufen, so dass sich die folgende Ausgabe für das Programm 1.1 ergibt: 3^4 = 81 10^5 = 100000 2.3^4 = 27.984100 1.3.5 Inline-Funktionen Da jeder Funktionsaufruf mit einer Laufzeiterhöhung (aufgrund des erforderlichen Stackmanagements) verbunden ist, wurden in C bei zeitkritischen Aufgabenstellungen oft Makros anstelle von Funktionen verwendet. Jeder Makroaufruf wurde dann vom Präprozessor (Precompiler) durch die entsprechenden Anweisungen direkt im Code ersetzt. Die Verwendung von Makros ist jedoch ziemlich aufwendig und fehleranfällig, da bei einem Makroaufruf nur eine (etwas bessere) Ersetzung 19 1 Einführung in die Objektorientierung und C++ von Text stattfindet, was viele Nebeneffekte auslösen kann, wie beispielsweise die mehrmalige Auswertung der Argumente. C++ bietet nun die Möglichkeit, so genannte inline-Funktionen zu definieren, um die Vorteile von Makros (schnellere Ausführung, da Code der entsprechenden inline-Funktion an der Aufrufstelle eingefügt wird und somit das Stackmanagement entfällt) mit den Vorteilen von Funktionen (Auswertung der Argumente vor dem Funktionsaufruf) zu kombinieren. Die Deklaration von inline-Funktionen entspricht der normaler Funktionen, nur dass das Schlüsselwort inline am Beginn der Funktionsdeklaration angegeben wird. Programm 1.2 zeigt typische Seiteneffekte, die bei Makros, nicht aber bei inline-Funktionen auftreten können. Programm 1.2 – inline.cpp: Seiteneffekte von Makros, die bei inline-Funktionen nicht auftreten #include <stdio.h> #define quad_makro(zahl) inline zahl * zahl int quad_inline(int zahl) { return zahl*zahl; } int main(void) { int z; z = 3; printf("quad_makro(++z) = %d\n", quad_makro(++z) ); // quad_makro(++z) wird zu: ++z * ++z --> 4*5 z = 3; printf("quad_inline(++z) = %d\n", quad_inline(++z) ); // quad_inline(++z) wird zu: quad_line(4) --> 4*4 return(0); } Programm 1.2 würde folgendes ausgeben: quad_makro(++z) = 20 quad_inline(++z) = 16 Da die Anweisungen von inline-Funktionen sowie auch die von Makros direkt im Code eingefügt werden, sollten beide nur für kleine Aufgaben eingesetzt werden, da dies sonst bei häufigen Aufrufen zu einer „Codeaufblähung“ führt. 1.3.6 Referenzen/Referenz-Operator Zugriffsmöglichkeiten in C In C existieren prinzipiell zwei Arten des Zugriffs auf ein im Hauptspeicher (RAM) liegendes Datum (aus Sicht des C-Programmierers). Zum Verständnis werden beide hier noch einmal kurz vorgestellt: 1. Zugriff auf ein Datum direkt über eine Variable (einen Variablennamen) 20 int a; // Variable vom Typ Integer int b = 7; // Variable vom Typ Integer mit Initialisierung 1.3 Nicht-objektorientierte Erweiterungen in C++ a = b; // Zuweisung des Wertes einer Variablen an eine andere (1) b = 4; // Zuweisung eines Wertes an eine Variable (2) Dieser Code bewirkt den in Abbildung 1.8 gezeigten Sachverhalt. a (1 ) ? ? ? 7 b a (2 ) 7 b a 7 7 b 4 Abbildung 1.8: Zugriff auf ein Datum über eine Variable 2. Zugriff auf ein Datum über einen Zeiger, der auf das Datum zeigt int a; // Variable vom Typ Integer int b = 7; // Variable vom Typ Integer mit Initialisierung int* zgr; // Zeiger auf ein Datum vom Typ Integer zgr // Zeiger erhält die Adresse einer Variablen = &a; *zgr = b; (1) // Wertzuweisung an die vom Zeiger adressierte Variable (2) Dieser Code bewirkt den in Abbildung 1.9 gezeigten Sachverhalt. ? ? ? 7 ? ? ? a b z g r (1 ) a b z g r ? ? ? 7 & a a (2 ) b z g r 7 7 & a Abbildung 1.9: Zugriff auf ein Datum über einen Zeiger Zugriff auf ein Datum über eine Referenz in C++ Eine Referenz in C++ kann man sich als zweiten Namen oder als Alias einer Variablen, also eines beliebigen Speicherbereiches, vorstellen. Diesen Alias kann man in der gleichen Art und Weise verwenden wie die referenzierte Variable. Der folgende C++-Auszug zeigt eine Möglichkeit der Verwendung einer Referenz: int int a; b = 7; int& ref = a; ref = 4; // Variable vom Typ Integer // Variable vom Typ Integer mit Initialisierung // Referenz auf eine Variable vom Typ Integer // Wertzuweisung an Variable ’a’ über Variable ’ref’ Dieser Code bewirkt den in Abbildung 1.10 gezeigten Sachverhalt. D ie s e r S p e ic h e r p la tz k a n n ü b e r z w e i N a m e n : 'a ' o d e r 'r e f ' a n g e s p r o c h e n w e r d e n re f / a b ? ? ? 7 re f / a b 4 7 Abbildung 1.10: Zugriff auf ein Datum über eine Referenz 21 Kapitel 2 Allgemeines zu Qt Non quia difficilia sunt non audemus, sed quia non audemus difficilia sunt. (Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.) – Seneca Dieses Kapitel klärt zunächst einmal, was Qt überhaupt ist und welche Vorteile Qt gegenüber anderen GUI-Produkten1 besitzt, bevor der wichtige Qt-Begriff Widget eingeführt wird. Die nächsten Absätze gehen dann kurz auf die bei Qt mitgelieferte Dokumentation ein, bevor abschließend auf die Generierung von Qt-Programmen mit make sowie mit dem eigens von den Qt-Entwicklern angebotenen Tool tmake zur automatischen Erstellung von Makefiles eingegangen wird. 2.1 Was ist Qt und warum Qt? Qt ist eine einfache und portable C++-Klassenbibliothek zur GUI-Programmierung Qt ist eine von der norwegischen Firma Troll Tech entwickelte C++-Klassenbibliothek, die eine einfache und portable GUI-Programmierung ermöglicht. Manche Programmierer behaupten sogar, dass Qt die einfachste GUI-Programmierung überhaupt unter den vielen angebotenen GUI-Toolkits erlaubt. Daneben sind mit Qt entwickelte Programme sowohl unter allen Linux/Unix- wie allen Windows-Systemen lauffähig. Qt ist ein GUI-Toolkit GUI-Toolkits sind in der MS-Windows-Welt kaum bekannt, dafür aber um so mehr in der Unix-Welt. Der Grund hierfür ist, dass die Windows-GUI-Schnittstelle API schon von sich aus eine high-level-Schnittstelle ist, die z. B. Buttons, Laufbalken oder Funktionen zum Ändern von Farben und Fonts anbietet. 1 GUI steht für „Graphical User Interface“. 115 2 Allgemeines zu Qt Anders verhält sich dagegen die unter Unix angebotene Schnittstelle des X Window System, die zwar sehr flexibel ist, aber nur low-level-Funktionen anbietet, wie z. B. zum Zeichnen primitiver Graphiken (Linien, Rechtecke usw.) oder zum Setzen der Hinter- und Vordergrundfarbe. Diese X-Window-Schnittstelle bietet keine high-level-Funktionen zum Erzeugen von Buttons, Laufbalken, Dialogboxen usw. Dies ist der Grund, warum einige Toolkits entwickelt wurden, um die GUIProgrammierung unter Unix zu vereinfachen. Der bekannteste Toolkit dürfte Motif sein, was nicht nur ein Toolkit, sondern auch eine Spezifikation für ein bestimmtes „look-and-feel“ ist. Allerdings ist die Verwendung von Motif sehr schwierig und äußerst mühsam, was sich daran erkennen lässt, dass Motif-Programme wesentlich länger sind als Qt-Programme, die das gleiche leisten. Nichtsdestotrotz ist Motif ein Standard. Qt ist nun ein GUI-Toolkit, der dieses look-and-feel von Motif mit einer wesentlich einfacheren GUI-Programmierschnittstelle zur Verfügung stellt. Nun noch einmal zurück zum Windows-API, das Funktionen anbietet, um GUIElemente (wie Buttons, Menüs usw.) zu erzeugen, Farben zu ändern usw. Diese API-Schnittstelle ist zwar wesentlich einfacher als das direkte Programmieren des X Window System, aber sie ist immer noch nicht benutzerfreundlich genug. Daneben existiert noch die Microsoft Foundation Class (MFC), welche zwar highlevel-Funktionen anbietet, aber doch sehr komplex in ihrer Verwendung ist. Bei der Benutzung von MFC muss der Benutzer immer noch sehr viel Zeit aufwenden, um eine Bedienoberfläche zu erzeugen, statt sich auf den eigentlichen Kern seiner Aufgabe zu konzentrieren. Qt ist nun ein so genanntes application framework, das alle die eben erwähnten Nachteile vermeidet. Unter einem Framework versteht man ein komplettes Programmiersystem, das dem Programmierer die low-level-Arbeiten abnimmt. Dazu stellt es ihm eine Bibliothek von Klassen zur Verfügung, so dass er sich Objekte definieren kann, die genau ein user-interface-Element repäsentieren (wie z. B. einen Button oder ein Menü), und er so über die vom Programmiersystem bereitgestellten Konstrukte alle Anwenderinteraktionen mit diesen Elementen verwalten kann. Vorteile von Qt Für die Verwendung von Qt bei der Entwicklung neuer Software sprechen die folgenden Vorzüge: ❏ Qt ist für Unix-Systeme (wie Linux, FreeBSD oder Solaris) frei, wenn man freie Software für diese Systeme schreibt. ❏ Qt ist portabel und einfach. Programme, die mit Qt geschrieben werden, sind so- wohl unter Linux/Unix als auch unter Windows lauffähig, was z. B. für MFC nicht gilt, denn mit MFC entwickelte Programme sind nur unter WindowsSystemen lauffähig. Zudem stufen viele Programmierer, die sowohl mit MFC als auch mit Qt gearbeitet haben, Qt als einfacher ein. ❏ Qt ist schnell. Programme, die mit Qt geschrieben sind, laufen sehr schnell ab. 116 2.2 Der Begriff „Widget“ 2.2 Der Begriff „Widget“ Qt arbeitet mit so genannten Widgets. Dieser Begriff wird unter Unix für Windows (Fenster) verwendet: „Widget“ ist eine Wortschöpfung aus den beiden Begriffen „Window“ und „Gadget“ (entspricht Controls unter Windows-Betriebssystemen). Nahezu alles, was man auf einer in Qt geschriebenen Oberfläche sieht, ist ein Widget: Buttons, Laufbalken, Dialogboxen usw. Widgets können ihrerseits wieder Subwidgets enthalten, wie z. B. Buttons oder Texteingabefelder in einer Dialogbox. In Qt ist ein Widget ein Objekt einer Klasse, die von der Klasse QWidget abgeleitet ist. Qt enthält viele vordefinierte Widgets, allerdings kann der Qt-Programmierer auch seine eigenen Widgets definieren. 2.3 Die Qt-Online-Dokumentation im HTML-Format Qt bietet eine hervorragende Online-Dokumentation im HTML-Format an. Deswegen ist es in dieser Qt-Einführung auch nicht notwendig, eine Qt-Referenz anzugeben, da mit jeder Qt-Distribution eine vollständige Online-Qt-Referenz mitgeliefert wird. Um diese Online-Dokumentation zu lesen, muss ein Web-Browser wie z. B. Netscape Navigator verwendet werden. Andere Browser, wie z. B. arena oder lynx unter Linux sind auch möglich, da die Qt-Online-Dokumentation weder spezielle HTML-Konstrukte verwendet noch Java oder JavaScript voraussetzt. Abbildung 2.1: Startseite der Qt-Referenz-Dokumentation 117 2 Allgemeines zu Qt Im Browser ist dann zuerst die Datei index.html im Verzeichnis doc der entsprechenden Qt-Installation zu öffnen (unter Linux/Unix-Systemen meist: /usr/lib/qt/doc/html bzw. /usr/lib/qt2/doc/html) um die Titelseite der Qt-Dokumentation einzublenden (siehe auch Abbildung 2.1). Um einen Eindruck zu bekommen, wie der Qt-Klassenbaum organisiert ist, sollte man zunächst den Punkt Annotated Class List anklicken. Man bekommt dann eine Liste aller Qt-Klassen, die public sind, mit einer einzeiligen Kurzbeschreibung angezeigt. Später, nachdem man mit Qt etwas mehr vertraut ist, kann man dann meist direkt von der Startseite zum Punkt Alphabetical Class List wechseln. Die dann eingeblendete Liste enthält keine Kurzbeschreibung und zeigt mehr Klassen auf einer Seite. Um einen ersten Eindruck über die Beschreibung der einzelnen Klassen zu bekommen, kann man z. B. auf den Link QButton klicken. QButton ist die Klasse, die für die Erzeugung von Buttons und deren Interaktionen mit dem Programm zuständig ist (siehe auch Abbildung 2.2). In Abbildung 2.2 sieht man als erste Zeile eine Kurzbeschreibung der jeweiligen Klasse. In der zweiten Zeile ist dann der Name der Headerdatei angegeben, in der diese Klasse definiert ist. Es folgt der Name der Basisklasse, von der diese Klasse abgeleitet ist, bevor in der nächsten Zeile eine Liste der Klassen angegeben ist, die wiederum von dieser Klasse (hier QButton) abgeleitet sind, was in Abbildung 2.2 die Klassen QCheckBox, QPushButton, QRadioButton und QToolButton sind. Der Link List of all member functions ist wichtig für den Fall, dass man einen Überblick über alle Memberfunktionen haben möchte, also nicht nur die Memberfunk- Abbildung 2.2: Die Referenz-Dokumentation für QButton 118 2.4 Die Qt-Dokumentation als Postscript-Datei tionen, die in der Klasse selbst definiert sind, sondern auch über die, welche diese Klasse von ihren übergeordneten Klassen erbt. Anschließend folgt eine Liste aller Public Members, die direkt in dieser Klasse definiert sind, sowie etwaige Listen von Public Slots, Signals oder Protected Members, die diese Klasse anbietet. Nach diesen Listen wird eine detaillierte Beschreibung der entsprechenden Klasse gegeben, die oft ganze Beispiele enthält, wie diese Klasse zu verwenden ist. 2.4 Die Qt-Dokumentation als Postscript-Datei Die Qt-Herstellerfirma Troll Tech bietet eine sehr gute Qt-Dokumentation als Postscript-Dateien auf ihrem Webserver http://www.trolltech.com zum Herunterladen an. 2.5 Kompilieren von Qt-Programmen Um Qt-Programme zu kompilieren, existieren zwei Möglichkeiten: ❏ die direkte Eingabe der Kommandozeile, was mit der Zeit sehr mühsam ist, oder aber ❏ das Arbeiten mit Makefiles. Direkte Eingabe der Kommandozeile Hier wird nur exemplarisch die Programmgenerierung für den Compiler Visual C++ (auf Windows-Betriebssystemen) und den Compiler GNU C++ (auf Unix-Systemen) vorgestellt. Daneben existieren weitere Möglichkeiten der Programmgenerierung, wie z. B. für den Compiler Borland C++ (auf Windows-Betriebssystemen) und für nahezu alle in der Unix-Welt bekannten Compiler. Diese werden hier nicht alle vorgestellt. Jedoch entspricht die Programmgenerierung auch auf für diese Compiler im Wesentlichen der hier vorgestellten Vorgehensweise. Arbeitet man mit dem Microsoft Visual-C++-Compiler unter einem Windows-Betriebssystem, muss man die beiden folgenden Kommandozeilen eingeben, wenn Qt im Directory c:nqt installiert wurde. cl -c -nologo -W3 -O1 -DNO_DEBUG -I"C:\qt\include" -Fo prog.obj prog.cpp link /NOLOGO /SUBSYSTEM:windows /OUT:myprog.exe myprog.obj C:\qt\lib\qt.lib user32.lib gdi32.lib comdlg32.lib imm32.lib ole32.lib uuid.lib wsock32.lib Auf Unix-Systemen sollte zunächst die Environmentvariable QTDIR gesetzt werden (z. B. export QTDIR=/usr/lib/qt oder export QTDIR=/usr/lib/qt2). Um dann ein Qt-Programm zu kompilieren, muss die folgende Kommandozeile eingegeben werden: c++ -I$QTDIR/include -L$QTDIR/lib -lqt -o prog prog.cpp 119 2 Allgemeines zu Qt Abhängig vom jeweiligen Unix-System kann diese Kommandozeile auch etwas anders aussehen. Die obige Kommandozeile gilt jedenfalls für alle Systeme, die den GNU C++-Compiler verwenden. Arbeiten mit Makefiles In diesem Fall ist das von Firma Troll Tech zur Verfügung gestellte Tool tmake sehr hilfreich. Für tmake muss man nur eine entsprechende .pro-Datei erstellen, wie z. B. die folgende Datei myprog.pro: TEMPLATE = app CONFIG = qt warn_on release HEADERS = cannon.h gamebrd.h lcdrange.h SOURCES = cannon.cpp gamebrd.cpp lcdrange.cpp main.cpp unix:LIBS= -lm TARGET = myprog Um sich nun das entsprechende Makefile2 erstellen zu lassen, muss man dann nur noch folgendes aufrufen ❏ unter Windows-Betriebssystemen: tmake myprog.pro -o Makefile -win32 ❏ unter Linux/Unix-Betriebssystemen: tmake myprog.pro -o Makefile -unix Das von tmake erzeugte Makefile hat z. B. für Windows-Betriebssysteme, unter denen mit Visual-C++ gearbeitet wird, folgendes Aussehen (aus Platzgründen etwas komprimiert): ####### Compiler, tools and options CC = cl CXX = cl CFLAGS = -nologo -W3 -O1 -DNO_DEBUG CXXFLAGS= -nologo -W3 -O1 -DNO_DEBUG INCPATH = -I"$(QTDIR)\include" LINK = link LFLAGS = /NOLOGO /SUBSYSTEM:windows LIBS = $(QTDIR)\lib\qt.lib user32.lib gdi32.lib comdlg32.lib imm32.lib ole32.lib uuid.lib wsock32.lib MOC = moc ZIP = zip -r -9 ####### Files HEADERS = cannon.h gamebrd.h lcdrange.h SOURCES = cannon.cpp gamebrd.cpp lcdrange.cpp main.cpp OBJECTS = cannon.obj gamebrd.obj lcdrange.obj main.obj SRCMOC = moc_cannon.cpp moc_gamebrd.cpp moc_lcdrange.cpp OBJMOC = moc_cannon.obj moc_gamebrd.obj moc_lcdrange.obj DIST = TARGET = myprog.exe 2 Das Tool make und die Syntax von Makefiles ist im Buch „Linux-Unix Profitools“ von Helmut Herold (Addison-Wesley) detailliert beschrieben. 120 2.5 Kompilieren von Qt-Programmen ####### Implicit rules .SUFFIXES: .cpp .cxx .cc .c .cpp.obj: $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $< .cxx.obj: $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $< .cc.obj: $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $< .c.obj: $(CC) -c $(CFLAGS) $(INCPATH) -Fo$@ $< ####### Build rules all: $(TARGET) $(TARGET): $(OBJECTS) $(OBJMOC) $(LINK) $(LFLAGS) /OUT:$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) moc: $(SRCMOC) tmake: Makefile Makefile: myprog.pro tmake myprog.pro -o Makefile dist: $(ZIP) myprog.zip myprog.pro $(SOURCES) $(HEADERS) $(DIST) clean: -del cannon.obj -del gamebrd.obj -del lcdrange.obj -del main.obj -del moc_cannon.cpp -del moc_gamebrd.cpp -del moc_lcdrange.cpp -del moc_cannon.obj -del moc_gamebrd.obj -del moc_lcdrange.obj -del $(TARGET) ####### Compile cannon.obj: cannon.cpp cannon.h gamebrd.obj: gamebrd.cpp gamebrd.h lcdrange.h cannon.h lcdrange.obj: lcdrange.cpp lcdrange.h main.obj: main.cpp gamebrd.h lcdrange.h cannon.h moc_cannon.obj: moc_cannon.cpp cannon.h moc_gamebrd.obj: moc_gamebrd.cpp gamebrd.h lcdrange.h cannon.h moc_lcdrange.obj: moc_lcdrange.cpp lcdrange.h moc_cannon.cpp: cannon.h $(MOC) cannon.h -o moc_cannon.cpp moc_gamebrd.cpp: gamebrd.h $(MOC) gamebrd.h -o moc_gamebrd.cpp moc_lcdrange.cpp: lcdrange.h $(MOC) lcdrange.h -o moc_lcdrange.cpp 121 2 Allgemeines zu Qt Nachdem dieses Makefile automatisch erstellt wurde, muss man unter WindowsSystemen nur noch nmake aufrufen, um ein ausführbares Programm zu generieren. Die von tmake unter Linux/Unix-Systemen erzeugten Makefiles sehen weitgehend ähnlich aus, nur dass sie z. B. andere Pfadnamen für die Headerdateien und Bibliotheken sowie eventuell auch andere Makronamen im Makefile enthalten. Unter Linux/Unix muss man dann make aufrufen, um ein ausführbares Programm zu generieren. 122 Kapitel 6 Vordefinierte Dialogfenster Genau betrachtet, ist alles Gespräch nur Selbstgespräch. – C. Morgenstern Ein Dialogfenster ist ein Widget, das für eine spezielle Kommunikation mit dem Benutzer ausgelegt ist, wie z. B. Auswahl einer bestimmten Farbe oder einer Datei. Qt bietet für solche typischen Kommunikationen mit dem Benutzer eine ganze Reihe von vordefinierten Dialogfenstern an, die schon mit entsprechenden Auswahlmöglichkeiten und/oder Buttons versehen sind und so dem Qt-Programmierer eine Menge Arbeit abnehmen. Die wichtigsten von Qt vordefinierten Dialogfenster sind: QDialog: Basisklasse für vordefinierte Dialogfenster QColorDialog: zur Auswahl einer Farbe QFileDialog: zur Auswahl einer Datei (z. B. zum Öffnen oder Speichern) QFontDialog: zur Auswahl eines Font (Zeichensatzes) QMessageBox: zur Anzeige von kurzen Informationen, die der Benutzer durch Drücken der dazu angebotenen Buttons bestätigen muss. QTabDialog: zur Stapelung von Widgets im Karteikartenformat, von denen über eine Karteikartenreiterleiste (Tableiste) immer eines in den Vordergrund gebracht werden kann. QWizard: zum Blättern in einer vorgegebenen Menge von Widgets. Dabei kann immer nur eine Seite vor- bzw. zurückgeblättert werden. Es wird dabei immer nur die aktuelle Seite angezeigt, während die anderen Seiten nicht sichtbar sind. QPrinter: zum Drucken mit möglichen Druckereinstellungen QInputDialog: für einfache Eingaben, wie z. B. Zahlen, Text oder Auswahl aus einer vorgegebenen Liste QProgressDialog: zur Anzeige in Form eines Prozentbalkens, wie weit eine bestimmte Aktion schon fortgeschritten ist 417 6 Vordefinierte Dialogfenster 6.1 Die Basisklasse QDialog Zunächst soll hier der Begriff modal geklärt werden, denn jedes Dialogfenster kann entweder modal oder nicht-modal sein: ❏ Ein nicht-modaler Dialog ist ein normales Window, das, während es eingeblendet ist, ein gleichzeitiges Arbeiten in anderen Windows dieses Programms zulässt. ❏ Ein modaler Dialog dagegen ist ein Window, das kein gleichzeitiges Arbeiten mit anderen Windows zulässt, während es eingeblendet ist. Erst nach der Beendigung eines modalen Dialogfensters ist es dem Benutzer wieder erlaubt, Aktivitäten in anderen Windows dieses Programms durchzuführen. Konstruktor und Methoden der Basisklasse QDialog Die Klasse QDialog bietet einen Konstruktor an: QDialog(QWidget *parent=0, const char *name=0, bool modal=false, WFlags f=0) Der Parameter modal legt dabei fest, ob es sich um einen modalen oder nichtmodalen Dialog handelt. Die Klasse QDialog bietet den folgenden enum-Datentyp, der für das Resultat eines modalen Dialogs vorgesehen ist: enum DialogCode { Rejected, Accepted }; Wichtige Methoden, die die Klasse QDialog anbietet, sind: int exec(): startet den entsprechenden Dialog und liefert die Antwort des Benutzers auf diesen Dialog als Rückgabewert. Der Aufruf von exec() ist identisch mit einem Aufruf show(), gefolgt von einem result()-Aufruf. Während diese Funktion für modale Dialoge sehr nützlich ist, macht sie keinen Sinn für nicht-modale Dialoge. Der Rückgabewert von exec() zeigt an, wie der Dialog beendet wurde: QDialog::Accepted (Button OK wurde gedrückt) bzw. QDialog::Rejected (Button Cancel wurde gedrückt). int result() const: liefert das Resultat des Dialogs als Rückgabewert. Wie exec() macht auch diese Methode nur Sinn bei modalen Dialogen. setResult(int) protected: setzt das Resultat des Dialogs auf Wert r. Die Klasse QDialog bietet unter anderem die folgenden Slotroutinen an: accept() virtual protected slot: schließt den Dialog und setzt das Resultat auf den Wert Accepted; entspricht dem Aufruf done(Accepted). reject() virtual protected slot: schließt den Dialog und setzt das Resultat auf den Wert Rejected; entspricht dem Aufruf done(Rejected). done(int r) virtual protected slot: schließt den Dialog und setzt das Resultat auf den Wert r; entspricht dem Aufruf hide(), gefolgt von setResult(r). Beispiel: Einblenden eines modalen oder nicht-modalen Dialogfensters Programm 6.1 ermöglicht es dem Benutzer, sich ein modales oder ein nicht-modales Dialogfenster anzeigen zu lassen. Die Voreinstellung ist das Einblenden eines nicht- 418 6.1 Die Basisklasse QDialog Abbildung 6.1: Modales Dialogfenster von Programm 6.1 mit Anzeige der Benutzerwahl (rechts) modalen Dialogfensters. Wird beim Aufruf dieses Programms die Option -m angegeben, wird ein modales Dialogfenster eingeblendet, wie es im linken Teil der Abbildung 6.1 gezeigt ist. Nachdem der Benutzer einen der beiden Buttons angeklickt hat, wie z. B. den OK-Button, wird ihm in einem Nachrichtenfenster (Messagebox) seine Auswahl nochmals bestätigt (siehe auch rechter Teil der Abbildung 6.1). Programm 6.1 – dialog.cpp: Demoprogramm zur Klasse QDialog #include <qwidget.h> #include <qapplication.h> #include <qdialog.h> #include <qpushbutton.h> #include <qmessagebox.h> //.............................................................. MeinDialog class MeinDialog : public QDialog { public: MeinDialog::MeinDialog( QWidget *parent, QString name, bool modal=true ) : QDialog( parent, name, modal ) { QPushButton *ok = new QPushButton( "OK", this ); ok->setGeometry( 10,10, 100,30 ); connect( ok, SIGNAL(clicked()), SLOT(accept()) ); if ( modal ) { QPushButton *cancel = new QPushButton( "Cancel", this ); cancel->setGeometry( 10,60, 100,30 ); connect( cancel, SIGNAL(clicked()), SLOT(reject()) ); } } }; //.................................................................... main int main( int argc, char *argv[] ) { 419 6 Vordefinierte Dialogfenster QApplication a( argc, argv ); QWidget *w = new QWidget; w->setGeometry( 10, 10, 300, 300 ); w->setPalette( QPalette( Qt::blue, Qt::blue ) ); w->show(); if ( argc > 1 && !strcmp( argv[1], "-m" ) ) { MeinDialog *modal = new MeinDialog( w, 0, true ); modal->setCaption( "Modaler Dialog" ); modal->setPalette( QPalette( Qt::red,Qt::red ) ); int r = modal->exec(); QString s; s.sprintf("Du hast ‘%s’ gedrueckt!", r == QDialog::Accepted ? "OK" : "Cancel" ); QMessageBox::information( 0, "Nur zu deiner Info", s ); } else { MeinDialog *nichtModal = new MeinDialog( w, 0, false ); nichtModal->setCaption( "Nicht-Modaler Dialog" ); nichtModal->setPalette( QPalette( Qt::red, Qt::red ) ); nichtModal->show(); } a.setMainWidget( w ); return a.exec(); } Übung: Dialog-Widget mit Checkboxen und mehreren Pushbuttons Erstellen Sie ein Programm dialog2.cpp, das ein Dialog-Widget mit Checkboxen einblendet, die der Benutzer ein- und ausschalten kann, sowie mit mehreren Buttons, die ihn seine Auswahl z. B. bestätigen oder ignorieren lassen. Unter Zuhilfenahme dieses Widget soll dann der Benutzer in den Checkboxen Länder auswählen können, zu denen er Flaggen angezeigt haben möchte (siehe auch Abbildung 6.2). Klickt der Benutzer auf den Ok-Button, werden ihm die Flaggen zu den Ländern angezeigt, die er in den Checkboxen ausgewählt hat. Bei einem Klick auf den Button Europäische sollen ihm in jedem Fall alle europäischen Flaggen und eventuell Abbildung 6.2: Eigenes Dialog-Widget zur Auswahl von Länderflaggen 420 6.2 Klasse QColorDialog zur Auswahl einer Farbe zusätzlich angeklickte Länderflaggen angezeigt werden. Klickt der Benutzer auf den Button Alle, sollen ihm unabhängig von seiner Auswahl in den Checkboxen alle Länderflaggen angezeigt werden. Ein Klick auf den Cancel-Button beendet unabhängig von der vorgenommenen Auswahl das Programm ohne jegliche Anzeige von Länderflaggen. 6.2 Klasse QColorDialog zur Auswahl einer Farbe Die Klasse QColorDialog bietet keine Konstruktoren an, sondern nur statische Funktionen, wie z. B. die Methode getColor(), die ein Dialogfenster zur Auswahl einer Farbe einblendet: QColor QColorDialog::getColor(QColor initial, QWidget *parent=0, const char *name=0) Diese Funktion blendet ein modales Dialogfenster ein, das dem Benutzer eine Farbe auswählen lässt (siehe auch Abbildung 6.3). In diesem Dialogfenster ist die Farbe, die mit dem Parameter initial übergeben wird, voreingestellt. Die vom Benutzer ausgewählte Farbe liefert diese Funktion dann als Rückgabewert, nachdem dieser den Ok-Button gedrückt hat und das Dialogfenster wieder ausgeblendet wurde. Hat der Benutzer den Cancel-Button gedrückt, liefert diese Funktion einen ungültigen Farbenwert, der sich mit der von der Klasse QColor angebotenen Methode isValid() erkennen lässt. Neben der statischen Methode getColor() bietet die Klasse QColorDialog noch einige weitere statische Methoden an, wie z. B.: QRgb QColorDialog::getRgba(QRgb initial, bool *ok=0, QWidget *parent=0, const char *name=0) static: blendet wie getColor() ein modales Dialogfenster ein, das dem Benutzer eine Farbe auswählen lässt. Anders als bei getColor() hat der Benutzer hier noch die Möglichkeit, einen Alpha-Kanal (unterhalb des Blue-Eingabefelds) festzulegen. Ist für ok kein Nullzeiger angegeben, so wird *ok auf true gesetzt, wenn der Benutzer den Ok-Button gedrückt hat, bzw. auf false , wenn er den Cancel-Button gedrückt hat. int QColorDialog::customCount() static: liefert die Anzahl der als Custom colors im QColorDialog-Widgets festgelegten Farben. QRgb QColorDialog::customColor(int i) static: liefert die i-te festgelegte Farbe aus den Custom colors des QColorDialog-Widget. QColorDialog::setCustomColor(int i, QRgb c) static: setzt die i-te Farbe von Custom colors im QColorDialog-Widget auf den QRgb-Wert c. Programm 6.2 ist ein Demonstrationsprogramm zur Klasse QColorDialog. Dieses Programm bietet im Hauptfenster eine Widget-Fläche mit einem Button an, mit dem man sich ein QColorDialog-Fenster (siehe auch Abbildung 6.3) einblenden lassen kann, um eine neue Farbe auszuwählen. Nach abgeschlossener Auswahl und Bestätigung dieser Wahl mit dem Ok-Button wird die neu gewählte Farbe in 421 6 Vordefinierte Dialogfenster Abbildung 6.3: Ein QColorDialog-Fenster der Widget-Fläche des Hauptfensters als Hintergrundfarbe angezeigt (siehe auch Abbildung 6.4). Die zu Beginn voreingestellte Hintergundfarbe ist Weiß. Programm 6.2 – colordialog.cpp: Demoprogramm zur Auswahl einer Farbe mit QColorDialog #include <qwidget.h> #include <qapplication.h> #include <qpushbutton.h> #include <qcolordialog.h> //............................................................... MeinFarbe Abbildung 6.4: Hauptfenster des Programms 6.2 422 6.3 Klasse QFileDialog zur Auswahl einer Datei class MeinFarbe : public QWidget { Q_OBJECT public: MeinFarbe::MeinFarbe() : QWidget( 0, 0) { setBackgroundColor( aktFarbe = Qt::white ); farbeButton = new QPushButton( "Neue Farbe", this ); connect( farbeButton, SIGNAL( clicked() ), SLOT( neueFarbe() ) ); setGeometry( 0, 0, 400, 400 ); } private slots: void neueFarbe() { QColor neuFarbe; neuFarbe = QColorDialog::getColor( aktFarbe, 0 ); if ( neuFarbe.isValid() ) { setBackgroundColor( aktFarbe = neuFarbe ); repaint(); } } private: QPushButton *farbeButton; QColor aktFarbe; }; #include "colordialog.moc" //.................................................................... main int main( int argc, char *argv[] ) { QApplication a( argc, argv ); MeinFarbe *w = new MeinFarbe; w->show(); a.setMainWidget( w ); return a.exec(); } Übung: Anzeige eines Textes in einer über QColorDialog gewählten Farbe Erstellen Sie ein Programm colordialog2.cpp, das ähnlich zu Programm 6.2 einen Button Neue Farbe und zusätzlich ein Label mit einem Text einblendet. Bei jedem Klick auf den Button Neue Farbe soll ein QColorDialog-Fenster eingeblendet werden, in dem der Benutzer eine neue Farbe wählen kann. Bestätigt er hier seine gewählte Farbe mit den Ok-Button, soll ihm der Text im Label mit dieser Farbe angezeigt werden. 6.3 Klasse QFileDialog zur Auswahl einer Datei Die Klasse QFileDialog bietet ein vordefiniertes Dialogfenster zur Auswahl eines Dateinamens an. 423 6 Vordefinierte Dialogfenster Konstruktoren und Methoden der Klasse QFileDialog Die Klasse QFileDialog bietet zwei Konstruktoren an: QFileDialog(QWidget *parent=0, const char *name=0, bool modal=false): erzeugt ein QFileDialog-Widget. Ob es sich dabei um ein modales oder nicht-modales Dialogfenster handelt, kann mit dem Parameter modal festgelegt werden. QFileDialog(const QString& dirName, const QString& filter=QString::null, QWidget *parent=0, const char *name=0, bool modal=false): erzeugt ein QFileDialog-Widget. Der Parameter dirName legt den Namen des Directory fest, aus dem die entsprechenden Dateien (für eine Auswahl) anzuzeigen sind. Der Parameter filter spezifiziert den Filter, der für die Anzeige von Dateinamen zu benutzen ist. Als Filter sind dabei reguläre Ausdrücke erlaubt, wie sie in einem späteren Kapitel beschrieben sind. Dabei ist es auch erlaubt, Texte anzugeben, die zur Information für den Benutzer dienen. In diesem Fall muss der entsprechende reguläre Ausdruck am Ende des entsprechenden Textes in runden Klammern angegeben werden; so liefern z. B. die beiden folgenden Angaben die gleiche Anzeige von Dateinamen in dem QFileDialog-Widget, nur dass die erste Angabe etwas informativer ist: "Alle C-Header- und Quelldateien (*.[ch])" bzw. "*.[ch]". Es ist auch möglich, mehrere Filter anzugeben, indem man diese durch neue Zeilen oder zwei Semikola trennt, wie z. B. "C++ Dateien (*.cpp *.cc *.C *.cxx *.c++);;Headerdateien (*.h *.hxx *.h++)". Ob es sich dabei um ein modales oder nicht-modales Dialogfenster handelt, kann mit dem Parameter modal festgelegt werden. Wichtige Methoden, die die Klasse QFileDialog anbietet, sind: QString getOpenFileName(const QString& startWith=QString::null, const QString& filter=QString::null, QWidget *parent=0, const char *name=0) static: Diese statische Funktion, die man verwenden kann, um ein QFileDialog-Fenster einzublenden, ohne dass man ein eigenes QFileDialog-Objekt anlegt, findet sehr häufige Anwendung. Sie öffnet ein modales QFileDialog-Fenster und liefert den vom Benutzer ausgewählten Dateinamen zurück. Wenn startWith ein Directoryname ist, startet der Dialog in diesem Directory. Ist startWith der Pfadname einer existierenden Datei, startet der Dialog in dem zugehörigen Directory, wobei der entsprechende Dateiname schon als ausgewählt angezeigt wird. Ist startWith ein Leerstring startet der Dialog im Working Directory und beim erneuten Aufrufen immer in dem Directory, in dem das letzte QFileDialog-Fenster beendet wurde. Sollen nur bestimmte Dateinamen im Dialogfenster angezeigt werden, so muss für den Parameter filter ein entsprechender regulärer Ausdruck angegeben werden. Falls für filter der Wert QString::null eingestellt wird, werden alle Dateinamen des entsprechenden Directory im Dialogfenster angezeigt. Falls der Benutzer das Dialogfenster mit dem Drücken des Cancel-Button beendet, liefert diese Funktion den null-String als Rückgabewert. Nachfolgend ist ein Beispiel für den Aufruf dieser Methode gezeigt: 424 6.3 Klasse QFileDialog zur Auswahl einer Datei //... im Working-Directory alle C++-Dateien mit der Endung .cpp anzeigen QString d = QFileDialog::getOpenFileName( QString::null, "*.cpp", this ); if ( !d.isEmpty() ) { //... Benutzer hat eine existierende Datei ausgewählt } else { //... Benutzer hat das Dialogfenster mit dem Cancel-Button beendet } QStringList getOpenFileNames(const QString& filter=QString::null, const QString& dir=QString::null, QWidget *parent=0, const char *name=0) static: Diese statische Funktion entspricht weitgehend der Funktion getOpenFileName(), nur dass sie den Benutzer mehrere Dateien auswählen lässt und diese dann als Rückgabewert liefert, wie z. B.: QStringList s( QFileDialog::getOpenFileNames() ); //... Bearbeiten der Dateien in s QString getSaveFileName(const QString& startWith=QString::null, const QString& filter=QString::null, QWidget *parent=0, const char *name=0) static: Diese statische Funktion entspricht weitgehend der Funktion getOpenFileName(), nur mit dem einzigen Unterschied, dass hier der Benutzer auch eine nicht existierende Datei auswählen kann, was ja beim Sichern von Dateien unter einem neuen Namen auch unbedingt notwendig ist. QString getExistingDirectory(const QString& dir=QString::null, QWidget *parent=0, const char *name=0) static: Diese statische Funktion blendet ein Dialogfenster ein, in dem der Benutzer ein existierendes Directory auswählen kann, das sie als Rückgabewert liefert. Welches Directory dabei beim Start des Dialogfensters der Ausgangspunkt sein soll, kann mit dem Parameter dir festgelegt werden. Falls dir=null gilt, wird als Ausgangspunkt das Directory genommen, in dem das letzte QFileDialog-Fenster beendet wurde. setDir(const QString& pathstr) slot: legt einen Directorypfad für ein QFileDialog-Fenster fest. QString dirPath() const: liefert den aktuellen Directorypfad eines QFileDialog-Fensters zurück. setSelection(const QString& filename): markiert in einem QFileDialog-Fenster den Dateinamen filename als ausgewählt. Falls es sich bei filename um einen absoluten Pfadnamen handelt, so wird automatisch auch setDir() aufgerufen. QString selectedFile() const: liefert zu der in einem QFileDialogFenster ausgewählten Datei den absoluten Pfadnamen. Falls kein Dateiname ausgewählt wurde, wird der null-String zurückgegeben. setFilter(const QString& newFilter) slot: legt für ein QFileDialog-Fenster einen neuen Filter fest, der als regulärer Ausdruck anzugeben ist, wie dies bereits beim zweiten Konstruktor zuvor beschrieben wurde. 425 6 Vordefinierte Dialogfenster setMode(Mode newMode): legt für ein QFileDialog-Fenster einen neuen Modus fest. Für den Parameter newMode kann dabei eine der folgenden Konstanten angegeben werden: ❏ Directory: Auswahl von Directories ist erlaubt ❏ ExistingFile: Auswahl von existierenden Dateien ist erlaubt ❏ AnyFile: Angabe von beliebigen Dateinamen (ob existierend oder nicht) ist erlaubt ❏ DirectoryOnly: Nur Auswahl von Directories erlaubt; andere Dateien werden nicht angezeigt. ❏ ExistingFiles: wie ExistingFile, nur dass auch Auswahl mehrerer Dateien erlaubt ist addWidgets(QLabel *l, QWidget *w, QPushButton *b) protected: fügt bis zu drei Widgets unten in dem QFileDialog-Widget hinzu. l ist dabei ein (optionales) Label, welches unterhalb der Spalte angeordnet wird, in der sich die Texte File name und File type befinden. w ist ein (optionales) Widget, das unterhalb der Kombobox für den File type platziert wird. b ist ein (optionaler) Button, der unterhalb des Cancel-Button angesiedelt wird. Soll eines dieser optionalen Widgets nicht angezeigt werden, muss für den entsprechenden Parameter nur der Wert 0 angegeben werden. rereadDir(): zwingt ein QFileDialog-Fenster den entsprechenden Directoryinhalt erneut zu lesen. Dies kann notwendig sein, wenn sich der Directoryinhalt ändert, nachdem das QFileDialog-Fenster für dieses Directory schon eingeblendet war. Die Klasse QFileDialog bietet die folgenden Signale an: fileHighlighted(const QString&) signal: wird gesendet, wenn der Benutzer einen Dateinamen markiert. fileSelected(const QString&) signal: wird gesendet, wenn der Benutzer einen Dateinamen auswählt. dirEntered(const QString&) signal: wird gesendet, wenn der Benutzer ein neues Directory ausgewählt hat. Abbildung 6.5: QFileDialog-Fenster zur Auswahl einer Datei im Programm 6.3 426 6.3 Klasse QFileDialog zur Auswahl einer Datei Abbildung 6.6: Laden eines Bildes (links) bzw. eines Textes (rechts) im Programm 6.3 Die Klasse QFileDialog bietet noch weitere Methoden an, mit denen man z. B. unter Zuhilfenahme der Klasse QFilePreview eine Vorschau zu Dateien einblenden kann oder unter Verwendung der Klasse QFileIconProvider die Dateinamen abhängig von ihrem Inhalt mit entsprechenden Icons versehen kann. Auf eine tiefergehende Behandlung dieser Methoden wird hier verzichtet. Der interessierte Leser kann diese in der Qt-Online-Dokumentation nachschlagen. Beispiel: Editor, der Betrachtung/Konvertierung von Bildern ermöglicht Programm 6.3 ist ein Demonstrationsprogramm zur Klasse QFileDialog. Über ein QFileDialog-Fenster (siehe Abbildung 6.5) kann dabei der Benutzer sich eine Datei auswählen. Handelt es sich dabei um eine Bilddatei, deren Format Qt interpretieren kann, so wird ihm das entsprechende Bild angezeigt, wie dies z. B. im linken Teil von Abbildung 6.6 gezeigt ist. Kann Qt das Format der entsprechenden Datei nicht als ein ihm bekanntes Bildformat interpretieren, liest das Programm 6.3 diese Datei als Textdatei in ein QMultiLineEdit-Widget ein, welches das Editieren dieses Textes ermöglicht, wie dies z.B im rechten Teil von Abbildung 6.6 gezeigt ist. Das Speichern einer Datei ist dabei auch möglich, wie dies in Abbildung 6.7 gezeigt ist. Handelt es sich bei der entsprechenden Datei um ein Bild, so konvertiert das Programm 6.3 das Bild bei der Speicherung abhängig von der Dateiendung automatisch in das entsprechende Bildformat (.png, .gif, .bmp, .xbm, .xpm, .pnm). Programm 6.3 – filedialog.cpp: Texteditor, der auch Betrachtung und Konvertierung von Bildern ermöglicht #include <qapplication.h> #include <qlabel.h> #include <qmultilinedit.h> #include <qfiledialog.h> #include <qmenubar.h> 427 6 Vordefinierte Dialogfenster Abbildung 6.7: QFileDialog-Fenster zur Auswahl eines Dateinamens zur Speicherung im Programm 6.3 #include <qpopupmenu.h> #include <qtextstream.h> #include <qmessagebox.h> enum { SchliessenID=255, SpeichernID, SpeichernUnterID }; //========================================================================== // V i e w e r - K l a s s e //========================================================================== class Viewer : public QWidget { Q_OBJECT // notwendig, da Slots enthalten sind public: Viewer(); private slots: void schliessenSlot() { //............................ schliessenSlot if ( view != NULL ) { delete view; view = NULL; dateiName = ""; setzeTitel( "keine" ); dateiMenu->setItemEnabled( SchliessenID, false ); dateiMenu->setItemEnabled( SpeichernID, false ); dateiMenu->setItemEnabled( SpeichernUnterID, false ); } } void beendenSlot() { //............................... beendenSlot schliessenSlot(); qApp->quit(); void oeffnenSlot() { } //............................... oeffnenSlot QString name = QFileDialog::getOpenFileName( ".", "*", this ); if ( !name.isEmpty() ) { dateiName = name; schliessenSlot(); leseDatei(); dateiMenu->setItemEnabled( SchliessenID, true ); dateiMenu->setItemEnabled( SpeichernID, true ); dateiMenu->setItemEnabled( SpeichernUnterID, true ); 428 6.3 Klasse QFileDialog zur Auswahl einer Datei } } void speichernSlot() { //........................... speichernSlot if (view != NULL) speichereDatei( false ); void speichernUnterSlot() { } //................. speichernUnterSlot if (view != NULL) speichereDatei( true ); } protected: virtual void resizeEvent( QResizeEvent* ) { //........... resizeEvent if (view != NULL) { view->setGeometry( 0, menuBalken->height(), width(), height() - menuBalken->height() ); if ( istBild ) bildView->setGeometry( 0,0, width(),height()-menuBalken->height() ); else textView->setGeometry( 0,0, width(),height()-menuBalken->height() ); repaint(); } } private: void leseDatei() { //...................................... leseDatei QFile datei; if ( !dateiName.isEmpty() ) { datei.setName( dateiName ); setzeTitel( dateiName ); view = new QWidget( this ); if ( bild.load( dateiName ) ) { bildView = new QScrollView( view ); bildView->viewport()->setBackgroundColor( Qt::white ); QLabel *l = new QLabel( bildView->viewport() ); l->setPixmap( bild ); l->setFrameStyle( QFrame::Box | QFrame::Sunken ); l->setLineWidth( 4 ); l->resize( l->sizeHint() ); istBild = true; bildView->addChild( l ); bildView->setGeometry( 0,0, width(),height()-menuBalken->height() ); } else if ( datei.open(IO_ReadOnly) ) { QTextStream text( &datei ); // verwende einen text stream QString s; textView = new QMultiLineEdit( view ); while ( !text.eof() ) { s = text.readLine(); textView->insertLine( s ); } datei.close(); istBild = false; textView->setGeometry( 0,0,width(),height()-menuBalken->height() ); } view->setGeometry( 0, menuBalken->height(), width(), height() - menuBalken->height() ); 429 6 Vordefinierte Dialogfenster view->show(); } } void speichereDatei( bool neuerName ) { //............ speichereDatei if ( dateiName.isEmpty() || neuerName == true ) dateiName = QFileDialog::getSaveFileName( ".", "*", this ); if ( !dateiName.isEmpty() ) { setzeTitel( dateiName ); if ( istBild ) { QString extension = dateiName.mid( dateiName.findRev(’.’)+1 ).upper(); if ( !bild.save( dateiName, extension ) ) QMessageBox::information( this, "Fehler", extension+"-Format wird nicht unterstützt"); } else { QFile datei; datei.setName( dateiName ); if ( datei.open(IO_WriteOnly) ) { QString text = textView->text(); datei.writeBlock( text, strlen(text) ); datei.close(); } } } } void setzeTitel( QString dateiname ) { //................ setzeTitel QString s = "Viewer - Datei: "; s += dateiname; setCaption( s ); } //............................................... private-Variablen QMenuBar *menuBalken; QPopupMenu *dateiMenu; QString dateiName; QWidget *view; QMultiLineEdit *textView; QScrollView *bildView; QPixmap bild; bool istBild; }; #include "filedialog.moc" //========================================================================== // V i e w e r - K o n s t r u k t o r //========================================================================== Viewer::Viewer() { view = NULL; dateiName = ""; setzeTitel( "keine"); dateiMenu = new QPopupMenu; //... erzeugt ein Datei-Menue dateiMenu->insertItem( "Oe&ffnen...", this, SLOT( oeffnenSlot() ), CTRL+Key_O ); 430 6.4 Klasse QFontDialog zur Auswahl eines Font dateiMenu->insertItem( "S&chliessen", this, SLOT( schliessenSlot() ), CTRL + Key_W, SchliessenID ); dateiMenu->setItemEnabled( SchliessenID, false ); dateiMenu->insertSeparator(); dateiMenu->insertItem( "&Speichern", this, SLOT( speichernSlot() ), CTRL + Key_S, SpeichernID ); dateiMenu->setItemEnabled( SpeichernID, false ); dateiMenu->insertItem( "Speichern &unter...", this, SLOT( speichernUnterSlot() ), CTRL + Key_U, SpeichernUnterID ); dateiMenu->setItemEnabled( SpeichernUnterID, false ); dateiMenu->insertSeparator(); dateiMenu->insertItem( "&Beenden", this, SLOT( beendenSlot() ), CTRL+Key_Q ); menuBalken = new QMenuBar( this ); //... erzeugt einen Menue-Balken menuBalken->insertItem( "&Datei", dateiMenu ); } //========================================================================== // m a i n //========================================================================== int main( int argc, char* argv[] ) { QApplication myapp( argc, argv ); Viewer* mywidget = new Viewer(); mywidget->setGeometry( 10, 10, 600, 600 ); myapp.setMainWidget( mywidget ); mywidget->show(); return myapp.exec(); } Übung: Anzeige ausgewählter Dateinamen in einem Label Erstellen Sie ein Programm filedialog2.cpp, das eine Erweiterung zum Übungsprogramm colordialog2.cpp auf Seite 423 ist, indem es nicht nur einen Farbe-Button, sondern auch einen Dateinamen-Button zeigt. Klickt der Benutzer auf diesen zweiten Button, soll ihm ein QFileDialog-Widget eingeblendet werden, in dem er auch mehrere Dateinamen gleichzeitig auswählen kann (mit QFileDialog::getOpenFileNames()), indem er bei dem Anklicken der Dateinamen die Strg -Taste drückt. Nachdem der Benutzer seine Auswahl mit Ok bestätigt hat, sollen ihm die ausgewählten Dateinamen in der aktuellen Farbe angezeigt werden; siehe auch Abbildung 6.8. 6.4 Klasse QFontDialog zur Auswahl eines Font Die Klasse QFontDialog bietet ein vordefiniertes Dialogfenster zur Auswahl eines Font an. 431 6 Vordefinierte Dialogfenster Abbildung 6.8: Anzeige von ausgewählten Dateinamen in einem Label Wichtige Methoden der Klasse QFontDialog Die Klasse QFontDialog bietet keine public-Konstruktoren an, sondern nur eine statische Funktion getFont(), die ein Dialogfenster zur Auswahl eines Font einblendet und in zwei Varianten angeboten wird: QFont getFont(bool *ok, QWidget *parent=0,const char *name=0) static: Diese Funktion blendet ein modales Dialogfenster ein, das den Benutzer einen Font auswählen lässt (siehe auch Abbildung 6.10). Den vom Benutzer ausgewählten Font liefert diese Funktion dann als Rückgabewert, nachdem dieser den Ok-Button gedrückt hat und das Dialogfenster wieder ausgeblendet wurde. Ob der Benutzer den Ok-Button gedrückt hat, lässt sich am Wert des Parameters ok erkennen. Ist *ok=true, hat er den Ok-Button gedrückt; bei *ok=false hat er das QFontDialog-Fenster mit dem Cancel-Button beendet oder eben anders geschlossen. Bei *ok=false liefert diese Funktion den voreingestellten Font zurück. Beispiel: bool ok; QFont f = QFontDialog::getFont( &ok, this ); if ( ok ) { //... Benutzer hat einen neuen Font ausgewählt } else { //... Benutzer hat Dialogfenster mit Cancel-Button oder anders beendet } QFont getFont(bool *ok, const QFont& initial, QWidget *parent=0, const char *name=0) static: Diese Variante entspricht weitgehend der vorhergehenden Aufrufvariante, nur dass im QFontDialog-Fenster der über den Parameter initial übergebene Font voreingestellt wird. 432 6.4 Klasse QFontDialog zur Auswahl eines Font Abbildung 6.9: Angezeigtes Hauptfenster beim Start von Programm 6.4 Beispiel: bool ok; QFont f = QFontDialog::getFont( &ok, QFont( "Times", 12 ), this ); if ( ok ) { //... Benutzer hat einen neuen Font ausgewählt } else { //... Benutzer hat Dialogfenster mit Cancel-Button oder anders beendet } Abbildung 6.10: QFontDialog-Fenster zur Auswahl eines Font im Programm 6.4 433 6 Vordefinierte Dialogfenster Abbildung 6.11: Hauptfenster im Programm 6.4, nachdem Benutzer neuen Font gewählt hat Beispiel: Demonstrationsprogramm zur Klasse QFontDialog Programm 6.4 zeigt in seinem Hauptfenster (siehe Abbildung 6.9) in einem Label den gerade gesetzten Font in Form eines Beispieltextes (Text) an. Die dazugehörigen Font-Daten werden in einem darunter angeordneten Label angezeigt. Als letztes bietet dieses Programm noch einen Button an, mit dem man sich ein QFontDialog-Fenster einblenden lassen kann, um einen neuen Font auszuwählen. Drückt der Benutzer auf diesen Button, wird ihm ein solches neues QFontDialog-Fenster eingeblendet, in dem er nun seine entsprechenden Font-Einstellungen vornehmen kann, wie dies z. B. in Abbildung 6.10 gezeigt ist. Drückt der Benutzer in diesem QFileDialog-Fenster den Ok-Button, werden ihm im Hauptfenster der Beispieltext Text in seinem gewählten Font sowie die zugehörigen Font-Daten angezeigt (siehe auch Abbildung 6.11). Programm 6.4 – fontdialog.cpp: Demoprogramm zur Klasse QFontDialog #include <qwidget.h> #include <qapplication.h> #include <qvbox.h> #include <qpushbutton.h> #include <qlabel.h> #include <qfont.h> #include <qfontdialog.h> //................................................................ MeinFont class MeinFont : public QVBox { Q_OBJECT public: 434 6.4 Klasse QFontDialog zur Auswahl eines Font MeinFont::MeinFont() : QVBox( 0, 0) { //.................. Vertikaler Layoutmanger QVBox *v = new QVBox( this ); v->setSpacing( 20 ); v->setMargin( 20 ); v->setBackgroundColor( Qt::blue.light( 180 ) ); //.... Label zur Anzeige des aktuellen Fonts fontAnzeige = new QLabel( "Text", v ); fontAnzeige->setBackgroundColor( Qt::white ); fontAnzeige->setAlignment( AlignCenter ); aktFont = fontAnzeige->font(); //.... Label zur Anzeige der aktuellen Fontdaten fontDaten = new QLabel( "", v ); fontDaten->setText( fontToString() ); fontDaten->setAlignment( AlignCenter ); //.... Buttom zum Einblenden QFontDialog-Fensters fontButton = new QPushButton( "Neuer Font", v ); fontButton->setPalette( QPalette( Qt::red, Qt::red ) ); connect( fontButton, SIGNAL( clicked() ), SLOT( neuerFont() ) ); setGeometry( 0, 0, 400, 400 ); } private slots: void neuerFont() { QFont neuFont; bool ok; neuFont = QFontDialog::getFont( &ok, aktFont ); if ( ok ) { fontAnzeige->setFont( aktFont = neuFont ); fontAnzeige->repaint(); fontDaten->setText( fontToString() ); fontDaten->repaint(); } } private: QFont aktFont; QLabel *fontAnzeige; QLabel *fontDaten; QPushButton *fontButton; //... liefert die Font-Daten als String zurueck. //... Dazu ruft diese Funktion die von der Klasse QFont angebotenen //... Methoden family(), weight(), italic() pointSize(), //... underline() und strikeOut() auf. QString fontToString() { QString s, weight; switch ( aktFont.weight() ) { case QFont::Light: weight = "Light"; break; case QFont::Normal: weight = "Normal"; break; case QFont::DemiBold: weight = "DemiBold"; break; case QFont::Bold: weight = "Bold"; break; case QFont::Black: weight = "Black"; break; 435 6 Vordefinierte Dialogfenster } s.sprintf("%s-%s-%s-%d\n\n%sUnderline-%sStrikeout\n", (const char *)aktFont.family(), (const char *)weight, (const char *)aktFont.italic() ? "Italic" : "", aktFont.pointSize(), (const char *)aktFont.underline() ? "" : "No", (const char *)aktFont.strikeOut() ? "" : "No" ); return s; } }; #include "fontdialog.moc" //.................................................................... main int main( int argc, char *argv[] ) { QApplication a( argc, argv ); MeinFont *w = new MeinFont; w->setGeometry( 20, 20, 400, 400 ); w->show(); a.setMainWidget( w ); return a.exec(); } Übung: Erweiterung des Übungsprogramms aus Kapitel 6.4 um Fonts Erstellen Sie ein Programm fontdialog2.cpp, das eine Erweiterung zum Übungsprogramm filedialog2.cpp auf Seite 431 ist, indem es nicht nur einen Farbe-Button und einen Dateinamen-Button, sondern auch einen Font-Button zeigt. Klickt der Benutzer auf diesen dritten Button, soll ihm ein QFontDialog-Widget eingeblendet werden, in dem er sich einen entsprechenden Font für die Anzeige der Dateinamen im Label auswählen kann. 6.5 Klasse QMessageBox für Mitteilungen Die Klasse QMessageBox ermöglicht es, den Benutzer über Situationen, Ereignisse oder Bedingungen zu informieren, die eingetreten sind oder aber eintreten könnten. QMessageBox-Dialogfenster sind fast immer modal. Typen, Konstruktoren und Methoden der Klasse QMessageBox Die Klasse QMessageBox bietet zwei eigene enum-Datentypen an: enum Icon { NoIcon=0, Information=1, Warning=2, Critical=3 }: Diese Konstanten legen das Icon (Bildchen) fest, das im QMessageBox-Fenster anzuzeigen ist: NoIcon: kein Icon Information: (Buchstabe ,i‘ in einer Sprechblase) wird verwendet, wenn man dem Benutzer lediglich eine Information zukommen lassen möchte. 436 6.5 Klasse QMessageBox für Mitteilungen Warning: (Ausrufezeichen in einem Warnschild) wird verwendet, wenn man den Benutzer warnen möchte. Critical: (weißes ,x‘ in einem schwarzen Kreis) wird verwendet, um den Benutzer auf eine kritische Situation hinzuweisen, die eingetreten ist oder eintreten könnte. enum { Ok=1, Cancel=2, Yes=3, No=4, Abort=5, Retry=6, Ignore=7, ButtonMask=0x07, Default=0x100, Escape=0x200, FlagMask=0x300 }: Diese Konstanten identifizieren Texte bzw. Einstellungen für Buttons, die in einem QMessageBox-Fenster angezeigt werden. Die Klasse QMessageBox bietet zwei Konstruktoren an: QMessageBox(QWidget *parent=0, const char *name=0): erzeugt ein QMessageBox-Widget, das keinerlei Text, aber einen Button mit der Beschriftung Ok enthält. QMessageBox(const QString& caption, const QString& text, Icon icon, int button0, int button1, int button2, QWidget *parent=0, const char *name=0, bool modal=true, WFlags f=WStyle_DialogBorder): Bei dieser Konstruktor-Variante wird ein QMessageBox-Widget erzeugt, dessen Titel durch den Parameter caption und dessen Informationstext durch den Parameter text festgelegt ist. Für den Parameter icon ist eine der folgenden Konstanten anzugeben: ❏ QMessageBox::NoIcon ❏ QMessageBox::Information ❏ QMessageBox::Warning ❏ QMessageBox::Critical Für die drei Parameter button0, button1 und button2 ist eine der folgenden Konstanten anzugeben: ❏ QMessageBox::Ok ❏ QMessageBox::Cancel ❏ QMessageBox::Yes ❏ QMessageBox::No ❏ QMessageBox::Abort ❏ QMessageBox::Retry ❏ QMessageBox::Ignore Einer dieser drei Buttons kann mit bitweisem OR mit der Konstante QMessageBox::Default verknüpft werden, was ihn zum Default-Button macht. Der Default-Button ist der Button, auf den automatisch der Tastaturfokus eingestellt wird und der so direkt durch Drücken der - -Taste ausgewählt (gedrückt) werden kann. Einer dieser drei Buttons kann mit bitweisem OR mit der Konstante QMessage ESC -Taste verbindet. Dies Box::Escape verknüpft werden, was ihn mit der bedeutet, dass beim Drücken der ESC -Taste (auf der Tastatur) immer dieser Button aktiviert wird, so als ob man auf diesen Button mit der Maus geklickt hätte. Der Parameter modal schließlich legt fest, ob ein modales oder ein nicht-modales QMessageBox-Widget zu erzeugen ist. 437 6 Vordefinierte Dialogfenster Nachfolgend ist ein kleiner Codeausschnitt für ein Nachrichtenfenster gezeigt, das beim Beenden eines Editors eingeblendet wird, wenn der Benutzer den Editor verlassen möchte, ohne dass er zuvor seine Datei gesichert hat. QMessageBox mb( "Datei noch nicht gesichert", "Was soll geschehen?", QMessageBox::Information, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape ); mb.setButtonText( QMessageBox::Yes, "Sichern" ); mb.setButtonText( QMessageBox::No, "Nicht sichern" ); mb.setButtonText( QMessageBox::Cancel, "Abbrechen" ); switch ( mb.exec() ) { case QMessageBox::Yes: //... Datei speichern und Editor verlassen break; case QMessageBox::No: //... Datei nicht speichern und Editor verlassen break; case QMessageBox::Cancel: //... Datei nicht speichern und Editor nicht vwerlasse break; } Man kann jedoch auch direkt ein QMessageBox-Fenster einblenden, ohne explizit ein Objekt dazu mittels eines Konstruktors anzulegen. Dazu bietet Qt die folgenden statischen Methoden an: int information(QWidget *parent, const QString& caption, const QString& text, const QString& button0Text=QString::null, const QString& button1Text=QString::null, const QString& button2Text=QString::null, int defaultButtonNumber=0, int escapeButtonNumber=-1) static: blendet ein QMessageBox-Fenster des Typs Information ein, dessen Titel durch den Parameter caption und dessen Informationstext durch den Parameter text festgelegt wird. Die nächsten drei Parameter buttonXText spezifizieren den Text für die einzelnen Buttons (bis zu drei). Ist für button0Text kein Argument angegeben, wird hierfür ein Ok-Button angezeigt, während ein Weglassen der beiden letzten optionalen Buttons dazu führt, dass diese Buttons überhaupt nicht angezeigt werden. Der Parameter defaultButtonNumber spezifiziert dann den DefaultButton (0, 1 oder 2) und der Parameter escapeButtonNumber spezifiziert den Escape-Button (0, 1 oder 2). Diese Funktion liefert die Nummer des Button, den der Benutzer gedrückt hat, als Rückgabewert (0, 1 oder 2). int information(QWidget *parent, const QString& caption, const QString& text, int button0, int button1=0, int button2=0) static: blendet ein QMessageBox-Fenster des Typs Information ein, dessen Titel durch den Parameter caption und dessen Informationstext 438 6.5 Klasse QMessageBox für Mitteilungen durch den Parameter text festgelegt wird. Dieses QMessageBox-Fenster enthält bis zu drei Buttons, deren Text der Benutzer durch die entsprechenden Kennungen (Ok, Cancel, Yes, ...) festlegen kann. Die Angabe von 0 für einen der Parameter button0, button1 oder button2 legt fest, dass dieser Button nicht anzuzeigen ist. Diese Funktion liefert die Nummer des Button, den der Benutzer gedrückt hat, als Rückgabewert (0, 1 oder 2). int warning(QWidget *parent, const QString& caption, const QString& text, const QString& button0Text=QString::null, const QString& button1Text=QString::null, const QString& button2Text=QString::null, int defaultButtonNumber=0, int escapeButtonNumber=-1) static: entspricht der entsprechenden information()-Methode (siehe oben), nur dass das eingeblendete QMessageBoxFenster vom Typ Warning ist. int warning(QWidget *parent, const QString& caption, const QString& text, int button0, int button1=0, int button2=0) static: entspricht der entsprechenden information()-Methode (siehe oben), nur dass das eingeblendete QMessageBox-Fenster vom Typ Warning ist. int critical(QWidget *parent, const QString& caption, const QString& text, const QString& button0Text=QString::null, const QString& button1Text=QString::null, const QString& button2Text=QString::null, int defaultButtonNumber=0, int escapeButtonNumber=-1) static: entspricht der entsprechenden information()-Methode (siehe oben), nur dass das eingeblendete QMessageBoxFenster vom Typ Critical ist. int critical(QWidget *parent, const QString& caption, const QString& text, int button0, int button1=0, int button2=0) static: entspricht der entsprechenden information()-Methode (siehe oben), nur dass das eingeblendete QMessageBox-Fenster vom Typ Critical ist. about(QWidget *parent, const QString& caption, const QString& text) static: Diese statische Methode blendet ein QMessageBox-Widget mit dem Titel caption und dem Informationstext text ein, in dem sich lediglich ein Ok-Button befindet (siehe auch linken Teil in Abbildung 3.9 auf Seite 167). aboutQt(QWidget *parent, const QString& caption=QString::null) static: Diese statische Methode blendet ein QMessageBox-Widget mit dem Titel caption und einigen Informationen zu Qt (wie z. B. die Versionsnummer) als Informationstext ein; in diesem QMessageBox-Widget befindet sich lediglich ein Ok-Button (siehe auch rechten Teil in Abbildung 3.9 auf Seite 167). Nachfolgend werden nun noch einige Methoden vorgestellt, mit denen man nachträglich ein zuvor mit einem Konstruktor erzeugtes QMessageBox-Objekt entsprechend konfigurieren kann: setText(const QString& text): legt den anzuzeigenden Informationstext für ein QMessageBox-Objekt fest. 439 6 Vordefinierte Dialogfenster Abbildung 6.12: Hauptfenster im Programm 6.5 zur Konfiguration einer QMessageBox setIcon(Icon icon): legt das anzuzeigende Icon (NoIcon, Information, Warning, Critical) für ein QMessageBox-Objekt fest. setIconPixmap(const QPixmap& pixmap): ermöglicht es, ein benutzerdefiniertes Icon (pixmap) für ein QMessageBox-Objekt festzulegen. setButtonText(int button, const QString& text): legt in einem QMessageBox-Objekt für den entsprechenden button, der die hier angegebene Kennung (Ok, Cancel, Yes, No, Abort, Retry, Ignore) besitzt, den anzuzeigenden text fest. Beispiel: Demonstrationsprogramm zur Klasse QMessageBox Programm 6.5 bietet über eine Menüleiste alle möglichen Konfigurationen für ein QMessageBox-Widget an (siehe Abbildung 6.12). Nachdem der Benutzer eine neue Konfiguration über einen Eintrag in dieser Menüleiste vorgenommen hat, wird ihm das entsprechende QMessageBox-Widget eingeblendet (siehe auch Abbildung 6.13). Nachdem der Benutzer dieses QMessageBox-Widget mit einem Klick auf einen der drei Buttons beendet hat, wird ihm in einem neuen QMessageBox-Fenster vom Typ Information seine Auswahl bestätigt (siehe auch Abbildung 6.14). Abbildung 6.13: Anzeige des konfigurierten QMessageBox-Fensters im Programm 6.5 440 6.5 Klasse QMessageBox für Mitteilungen Abbildung 6.14: Anzeige der Benutzerwahl aus Abbildung 6.13 im Programm 6.5 Programm 6.5 – messagebox.cpp: Demoprogramm zur Klasse QMessageBox #include <qapplication.h> #include <qmenubar.h> #include <qpopupmenu.h> #include <qlineedit.h> #include <qmessagebox.h> #include <stdio.h> const int texteId = 0x1000; const int IconId = 0x2000; const int ButtonId = 0x3000; const int DefaultId = 0x4000; const int EscId = 0x5000; enum { CaptionId=texteId, InfotextId }; enum { NoIconId=IconId, InformationId, WarningId, CriticalId }; enum { OkId=ButtonId, CancelId, YesId, NoId, AbortId, RetryId, IgnoreId }; //......................................................... Klasse MyWidget class MyWidget : public QWidget { Q_OBJECT // notwendig, da Slots enthalten sind public: MyWidget() { //______________ MyWidget (Konstruktor) //.................. Initialisierungen caption = ""; escButton = 2; infoText = "Informationstext"; icon defaultButton = 0; = QMessageBox::NoIcon; button[0] = QMessageBox::Yes | QMessageBox::Default; button[1] = QMessageBox::No; button[2] = QMessageBox::Cancel | QMessageBox::Escape; //...............Texte-Menu texteMenu = new QPopupMenu; texteMenu->insertItem( "Caption", CaptionId ); texteMenu->insertItem( "Infotext", InfotextId ); QObject::connect( texteMenu, SIGNAL( activated( int ) ), this, SLOT( texteSlot( int ) ) ); lc = new QLineEdit( caption, this ); li = new QLineEdit( infoText, this ); lc->setGeometry(10, 30, 100, 30 ); li->setGeometry(10, 30, 100, 30 ); lc->hide(); li->hide(); QObject::connect( lc, SIGNAL( returnPressed() ), 441 6 Vordefinierte Dialogfenster this, SLOT( neuerCaptionSlot() ) ); QObject::connect( li, SIGNAL( returnPressed() ), this, SLOT( neuerInfoTextSlot() ) ); //................ Icon-Menu iconMenu = new QPopupMenu; iconMenu->insertItem( "NoIcon", NoIconId ); iconMenu->insertItem( "Information", InformationId ); iconMenu->insertItem( "Warning", WarningId ); iconMenu->insertItem( "Critcal", CriticalId ); iconMenu->setItemChecked( NoIconId, true ); QObject::connect( iconMenu, SIGNAL( activated( int ) ), this, SLOT( iconSlot( int ) ) ); //............ button-Menues for (int i=0; i<3; i++) { buttonMenu[i] = new QPopupMenu; buttonMenu[i]->insertItem( "Ok", OkId ); buttonMenu[i]->insertItem( "Cancel", CancelId ); buttonMenu[i]->insertItem( "Yes", YesId ); buttonMenu[i]->insertItem( "No", NoId ); buttonMenu[i]->insertItem( "Abort", AbortId ); buttonMenu[i]->insertItem( "Retry", RetryId ); buttonMenu[i]->insertItem( "Ignore", IgnoreId ); } buttonMenu[0]->setItemChecked( YesId, true ); buttonMenu[1]->setItemChecked( NoId, true ); buttonMenu[2]->setItemChecked( CancelId, true ); QObject::connect( buttonMenu[0], SIGNAL( activated( int ) ), this, SLOT( button0Slot( int ) ) ); QObject::connect( buttonMenu[1], SIGNAL( activated( int ) ), this, SLOT( button1Slot( int ) ) ); QObject::connect( buttonMenu[2], SIGNAL( activated( int ) ), this, SLOT( button2Slot( int ) ) ); //............. Default-Menu defaultMenu = new QPopupMenu; defaultMenu->insertItem( "Button0", DefaultId ); defaultMenu->insertItem( "Button1", DefaultId+1 ); defaultMenu->insertItem( "Button2", DefaultId+2 ); defaultMenu->setItemChecked( DefaultId+defaultButton, true ); QObject::connect( defaultMenu, SIGNAL( activated( int ) ), this, SLOT( defaultSlot( int ) ) ); //................. Esc-Menu escMenu = new QPopupMenu; escMenu->insertItem( "Button0", EscId ); escMenu->insertItem( "Button1", EscId+1 ); escMenu->insertItem( "Button2", EscId+2 ); escMenu->setItemChecked( EscId+escButton, true ); QObject::connect( escMenu, SIGNAL( activated( int ) ), this, SLOT( escSlot( int ) ) ); //............... Menu-Balken menuBalken = new QMenuBar( this ); 442 6.5 Klasse QMessageBox für Mitteilungen menuBalken->insertItem( "Texte", texteMenu ); menuBalken->insertItem( "Icon", iconMenu ); menuBalken->insertItem( "Button0", buttonMenu[0] ); menuBalken->insertItem( "Button1", buttonMenu[1] ); menuBalken->insertItem( "Button2", buttonMenu[2] ); menuBalken->insertItem( "Default", defaultMenu ); menuBalken->insertItem( "Esc", escMenu ); } private slots: void texteSlot( int s ) { //_______________________________ Slots switch ( s ) { case CaptionId : lc->show(); break; case InfotextId: li->show(); break; } } void neuerCaptionSlot() { caption = lc->text(); lc->hide(); neueMessageBox(); } void neuerInfoTextSlot() { infoText = li->text(); li->hide(); neueMessageBox(); } void iconSlot( int s ) { switch ( s ) { case NoIconId : icon = QMessageBox::NoIcon; break; case InformationId: icon = QMessageBox::Information; break; case WarningId : icon = QMessageBox::Warning; break; case CriticalId : icon = QMessageBox::Critical; break; } for (int i=NoIconId; i <= CriticalId; i++) iconMenu->setItemChecked( i, s == i ); neueMessageBox(); } void button0Slot( int s ) { buttonConfigure( s, 0); } void button1Slot( int s ) { buttonConfigure( s, 1); } void button2Slot( int s ) { buttonConfigure( s, 2); } void defaultSlot( int s ) { button[defaultButton] &= ~QMessageBox::Default; button[defaultButton=s-DefaultId] |= QMessageBox::Default; for (int i=DefaultId; i <= DefaultId+2; i++) defaultMenu->setItemChecked( i, s == i ); neueMessageBox(); } void escSlot( int s ) { button[escButton] &= ~QMessageBox::Escape; button[escButton=s-EscId] |= QMessageBox::Escape; for (int i=EscId; i <= EscId+2; i++) 443 6 Vordefinierte Dialogfenster escMenu->setItemChecked( i, s == i ); neueMessageBox(); } private: void buttonConfigure( int s, int n ) { switch ( s ) { case OkId : button[n] = QMessageBox::Ok; break; case CancelId: button[n] = QMessageBox::Cancel; break; case YesId : button[n] = QMessageBox::Yes; break; case NoId : button[n] = QMessageBox::No; break; case AbortId : button[n] = QMessageBox::Abort; break; case RetryId : button[n] = QMessageBox::Retry; break; case IgnoreId: button[n] = QMessageBox::Ignore; break; } if ( n == defaultButton ) button[n] |= QMessageBox::Default; if ( n == escButton ) button[n] |= QMessageBox::Escape; for (int i=OkId; i <= IgnoreId; i++) buttonMenu[n]->setItemChecked( i, s == i ); neueMessageBox(); } void neueMessageBox() { QString neuInfoText; neuInfoText.sprintf("%s\n\n\n" " (Button%d = Default-Button)\n" " (Button%d = Escape-Button)\n", (const char *)infoText, defaultButton, escButton); QMessageBox *mb = new QMessageBox( caption, neuInfoText, icon, button[0], button[1], button[2], this ); mb->setPalette( QPalette( Qt::red, Qt::red ) ); int ret = mb->exec(); delete mb; QString info = "Du hast den Button\""; switch ( ret ) { case QMessageBox::Ok: info+= "Ok"; break; case QMessageBox::Cancel: info+= "Cancel"; break; case QMessageBox::Yes: info+= "Yes"; break; case QMessageBox::No: info+= "No"; break; case QMessageBox::Abort: info+= "Abort"; break; case QMessageBox::Retry: info+= "Retry"; break; case QMessageBox::Ignore: info+= "Ignore"; break; } info += "\" gewaehlt"; QMessageBox::information( this, "Nur zur Info", info ); } QMenuBar *menuBalken; QPopupMenu *texteMenu, *iconMenu, *buttonMenu[3], *defaultMenu, *escMenu; QString caption, infoText; int button[3], defaultButton, escButton; QLineEdit *lc, *li; QMessageBox::Icon 444 icon; 6.5 Klasse QMessageBox für Mitteilungen Abbildung 6.15: Auswahl eines Landes über Messageboxen }; #include "messagebox.moc" //.................................................................... main int main( int argc, char* argv[] ) { QApplication myapp( argc, argv ); MyWidget*mywidget = new MyWidget(); mywidget->setGeometry( 10, 10, 400, 300 ); mywidget->setPalette( QPalette( Qt::lightGray, Qt::blue ) ); myapp.setMainWidget( mywidget ); mywidget->show(); return myapp.exec(); } Übung: Auswahl eines Landes und Anzeige dessen Flagge Erstellen Sie ein Programm messagebox2.cpp, das zunächst eine Messagebox einblendet, wie sie links in Abbildung 6.15 gezeigt ist. Klickt der Benutzer den Button Weiter, wird ihm eine nächste Wahlmöglichkeit gezeigt (siehe Mitte in Abbildung 6.15). Klickt der Benutzer auch hier wieder auf den Button Weiter, wird ihm eine dritte und letzte Wahlmöglichkeit gezeigt (siehe rechts in Abbildung 6.15). Sollte er sich auch hier nicht für ein Land entscheiden können und klickt nun auf den Button None, wird ihm schließlich noch eine letzte Messagebox (siehe Abbildung 6.16) eingeblendet, in der er lediglich mit einem Klick auf den Ok-Button das Programm beenden kann. Sollte der Benutzer sich aber in einer der drei Messageboxen aus Abbildung 6.15 für ein Land entschieden haben, wird ihm die Flagge dieses Landes als Icon in einer Messagebox eingeblendet, wie dies beispielhaft für die Länder „Britain“ und „USA“ in Abbildung 6.17 gezeigt ist. Abbildung 6.16: Messagebox, wenn Benutzer kein Land auswählte 445 6 Vordefinierte Dialogfenster Abbildung 6.17: Anzeige der Flagge des gewählten Landes in einer Messagebox 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat Die Klasse QTabDialog ermöglicht die Stapelung von Widgets im Karteikartenformat, von denen über eine Karteikartenreiterleiste (Tableiste) immer eines in den Vordergrund gebracht werden kann. Konstruktor und Methoden der Klasse QTabDialog Die Klasse QTabDialog bietet einen Konstruktor an: QTabDialog(QWidget *parent=0, const char *name=0, bool modal=false, Wflags f=0) erzeugt ein QTabDialog-Widget mit einem Ok-Button. Die übliche Vorgehensweise beim Programmieren einer QTabDialog-Anwendung ist die folgende: 1. Erzeugen eines QTabDialog-Widget (mit dem obigen Konstruktor). 2. Erzeugen von QWidget-Objekten für jede Seite, die in diesem QTabDialogWidget untergebracht werden sollen. 3. Einfügen der entsprechenden Subwidgets (eventuell unter Verwendung von Layout-Managern) in die einzelnen QWidget-Objekte der entsprechenden Seiten. 4. Aufrufen der Methode addTab(), um die einzelnen Seiten (QWidget-Objekte) in dem QTabDialog-Widget einzuordnen. 5. Einrichten der einzelnen Buttons (Apply, Cancel usw.) des QTabDialog-Widget und Verknüpfen der einzelnen Button-Signale mit den entsprechenden Slotroutinen. Wichtige Methoden, die die Klasse QTabDialog anbietet, sind: addTab(QWidget *child, const QString& label): fügt eine neue Seite (child) zu einem QTabDialog-Widget hinzu. label ist dabei die Beschriftung dieser Seite, die in der immer sichtbaren Tableiste für diese Seite (in Button-Form) angezeigt wird. Ein Klick auf diese Beschriftung bringt dann diese Seite in den Vordergrund. Innerhalb des Beschriftungstextes kann dabei ein Beschleuniger angegeben werden, indem dem entsprechenden Zeichen & vorangestellt wird, um so dem Benutzer eine schnelle Anwahl dieser Seite mittels Eingabe des ent Alt -Taste zu ermöglichen. sprechenden Zeichens bei gedrückter 446 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat Es ist darauf hinzuweisen, dass eine Seite in jedem Fall mit addTab() bzw. insertTab() in einem QTabDialog-Widget hinzuzufügen ist. Die alleinige Angabe des QTabDialog-Widget als Elternwidget bei der Erzeugung einer QWidget-Objekts (für eine Seite) reicht nicht aus. Eine solche Seite würde nicht im QTabDialog-Widget eingeordnet und damit auch nicht angezeigt. insertTab(QWidget *child, const QString& label, int index=1): entspricht der Methode addTab(), nur dass man hier eine Position (index) angeben kann, an der die entsprechende Seite einzufügen ist. Die Voreinstellung (index=-1) bedeutet, dass die entsprechende Seite am Ende eingefügt wird, wie dies auch bei addTab() geschieht. changeTab(QWidget *w, const QString& label): legt eine neue Beschriftung (label) für die Seite w fest. setOkButton() setOkButton(const QString& text): Beide Methoden fügen einen OkButton in jeder Seite des QTabDialog-Widget unten ein, wobei bei der zweiten Methode dieser Button nicht den Text Ok, sondern den hier angegebenen text enthält. Ist text ein null-String, wird kein Ok-Button eingeblendet. Wird der Ok-Button angeklickt, wird automatisch das Signal applyButtonPressed() geschickt, und die aktuellen Einstellungen aller Seiten des QTabDialog-Widget werden übernommen. Anschließend wird dann das QTabDialog-Widget ausgeblendet. setApplyButton() setApplyButton(const QString& text): Beide Methoden fügen einen Apply-Button in jeder Seite des QTabDialog-Widget unten ein, wobei jedoch bei der zweiten Methode dieser Button nicht den Text Apply, sondern eben den hier angegebenen text enthält. Wird der Apply-Button geklickt, wird automatisch das Signal applyButtonPressed() geschickt, und die aktuellen Einstellungen aller Seiten des QTabDialog-Widget werden übernommen. Anders als beim Anklicken des Ok-Button bleibt hier das QTabDialog-Widget sichtbar und wird nicht ausgeblendet. setCancelButton() setCancelButton(const QString& text): Beide Methoden fügen einen Cancel-Button in jeder Seite des QTabDialog-Widgets unten ein, wobei jedoch bei der zweiten Methode dieser Button nicht den Text Cancel, sondern eben den hier angegebenen text enthält. Ist text ein null-String, wird kein CancelButton eingeblendet. Bei einem Klick auf den Cancel-Button wird automatisch das Signal cancelButtonPressed() geschickt, und die Einstellungen aller Seiten des QTabDialog-Widget werden in die Zustände zurückgesetzt, die vorlagen, als das QTabDialog-Widget eingeblendet wurde, bzw. in die Zustände, die mit dem letzten Klicken des Apply-Button eingestellt wurden. Anschließend wird dann das QTabDialog-Widget ausgeblendet. setDefaultButton() setDefaultButton(const QString& text): Beide Methoden fügen einen Defaults-Button in jeder Seite des QTabDialog-Widget unten ein, wobei jedoch bei der zweiten Methode dieser Button nicht den Text Defaults, sondern den hier angegebenen text enthält. Ist text ein null-String, wird kein Defaults-Button 447 6 Vordefinierte Dialogfenster eingeblendet. Wird der Defaults-Button geklickt, wird automatisch das Signal defaultButtonPressed() geschickt, und die Einstellungen aller Seiten des QTabDialog-Widget sollten auf ihre Defaults (Voreinstellungen) zurückgesetzt werden. Wichtig ist hierbei, dass lediglich die Einstellungen im QTabDialogWidget zurückgesetzt werden sollten, diese aber noch nicht in der entsprechenden Anwendung übernommen werden sollten. Zum Übernehmen der vorgenommenen Einstellungen in der jeweiligen Applikation dienen der Ok- und Apply-Button, welche beide das Signal applyButtonPressed() schicken. setHelpButton() setHelpButton(const QString& text): Beide Methoden fügen einen HelpButton in jeder Seite des QTabDialog-Widget unten ein, wobei jedoch bei der zweiten Methode der Buttontext nicht Help, sondern der angegebene text ist. Ist text ein null-String, wird kein Help-Button eingeblendet. Wird der Help-Button geklickt, wird das Signal helpButtonPressed() geschickt, das mit einer Slotroutine verbunden werden sollte, die entsprechende Help-Information einblendet. showPage(QWidget *w): bringt Seite w des QTabDialog-Widgets in den Vordergrund, so dass sie sichtbar wird. Diese Methode kann bei der Verwendung von Beschleunigern (in der Tableiste) sehr nützlich sein. setTabEnabled(QWidget *w, bool enable): schaltet die Anwahlmöglichkeit der Seite w im QTabDialog-Widget ein (enable=true) bzw. aus (enable=false). Ist die Anwahl einer Seite ausgeschaltet, so wird deren Button in der Tableiste entsprechend blass dargestellt, um dem Benutzer anzuzeigen, dass er diese Seite nicht anwählen kann. QString tabLabel(QWidget *w): liefert die Beschriftung (in der Tableiste) der Seite w. setTabBar(QTabBar *tb) protected: ändert den Stil der Tableiste. Diese Methode muss dabei unbedingt aufgerufen werden, bevor irgendwelche Seiten zum QTabDialog-Widget hinzugefügt werden. Zum Ändern des Aussehens der Tableiste muss dabei z. B. folgender Codeausschnitt verwendet werden: // QTabBar *tb = new QTabBar( this ); .... Verschiedene Stilarten (in folg. 4 Zeilen ein // entfernen) // tb->setShape( QTabBar::RoundedAbove ); // tb->setShape( QTabBar::RoundedBelow ); // tb->setShape( QTabBar::TriangularAbove ); // tb->setShape( QTabBar::TriangularBelow ); setTabBar( tb ); Tiefergehende Informationen können Interessierte in der Qt-Online-Dokumentation bei der Klasse QTabBar nachschlagen Die Signale, die die Klasse QTabDialog anbietet, sind: applyButtonPressed() signal: wird geschickt, wenn der Apply- oder OkButton geklickt wird; siehe dazu auch die Beschreibung der Methoden setOkButton() und setApplyButton(). Dieses Signal sollte mit einer oder auch mehreren Slotroutinen verbunden werden, die die entsprechenden Einstellungen des QTabDialog-Widgets in die entsprechende Applikation übernehmen. 448 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat cancelButtonPressed() signal: wird geschickt, wenn der Cancel-Button geklickt wird; siehe dazu auch die Beschreibung der Methode setCancelButton(). Dieses Signal ist automatisch mit der Methode QDialog::reject() verbunden, welche das QTabDialog-Widget ausblendet. Da dieses Signal andeutet, dass alle vorgenommen Änderungen in den Einstellungen zu verwerfen sind, sollten die entsprechenden Einstellungen auch nicht in der Applikation übernommen werden. defaultButtonPressed() signal: wird geschickt, wenn der Defaults-Button geklickt wird; siehe dazu auch die Beschreibung der Methode setDefaultButton(). helpButtonPressed() signal: wird geschickt, wenn der Help-Button geklickt wird; siehe dazu auch die Beschreibung der Methode setHelpButton(). aboutToShow() signal: wird geschickt, bevor ein QTabDialog-Widget eingeblendet wird. Dieses Signal kann sinnvoll eingestezt werden, wenn man ein QTabDialog-Widget nur einmal erzeugt, und immer bei Bedarf einblendet, und ansonsten versteckt im Hintergrund hält. currentChanged(QWidget *w) signal: wird geschickt, wenn eine neue Seite sichtbar gemacht wird. Beispiel: Demonstrationsprogramm zur Klasse QTabDialog Programm 6.6 blendet ein Hauptfenster mit zwei Buttons ein, zwischen denen ein Label eingeschoben ist, das die aktuellen Einstellungen (Beantwortung der Fragen mit entsprechender Bewertung) anzeigt (siehe Abbildung 6.18). Dieses Programm erzeugt ein QTabDialog-Widget, das es immer bei einem Klick auf den Button TabDialog einblendet. Dieses QTabDialog-Widget enthält auf den ersten beiden Seiten einen kleinen Wissenstest: Auf Seite 1 eine Frage zum Allgemeinwissen (siehe links in Abbildung 6.19) und auf Seite 2 zwei Fragen zur Mathematik (siehe rechts in Abbildung 6.19). Klickt der Benutzer auf den Übernehmen-Button, wird seine Antwort ausgewertet und ihm im Label des Hauptfensters die Bewertung seiner Auswahl (richtig oder falsch) angezeigt. Auf der dritten Seite bietet dieses Abbildung 6.18: Hauptfenster des Programms 6.6 449 6 Vordefinierte Dialogfenster Abbildung 6.19: Seite 1 und Seite 2 des QTabDialog-Widgets im Programm 6.6 QTabDialog-Widget einen Button Farbauswahl an, der bei einem Klick ein QColorDialog-Widget (siehe z. B. Abbildung 6.3) einblendet, in dem der Benutzer sich eine Farbe auswählen kann, welche dann in einem Label unter diesem Button (sie- Abbildung 6.20: Seite 3 des QTabDialog-Widgets im Programm 6.6 450 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat he Abbildung 6.20) angezeigt wird. Bei einem Klick auf den Button Übernehmen wird diese Farbe in dem Label des Hauptfensters als Hintergrundfarbe verwendet. In allen drei Seiten haben die einzelnen unten angezeigten Buttons die gleichen Auswirkungen: Ok: Die aktuellen Einstellungen aus allen drei Seiten werden übernommen und ausgewertet. Anschließend wird das QTabDialog-Widget ausgeblendet. Voreinstellung: Alle drei Seiten werden auf ihre Voreinstellungen zurückgesetzt Übernehmen: Die aktuellen Einstellungen aus allen drei Seiten werden übernommen, ohne dass das QTabDialog-Widget ausgeblendet wird. Abbrechen: Das QTabDialog-Widget wird ausgeblendet, ohne dass die vorgenommenen Einstellungen übernommen werden. Programm 6.6 – tabdialog.cpp: Demoprogramm zur Klasse QTabDialog #include <qapplication.h> #include <qvbox.h> #include <qlabel.h> #include <qlineedit.h> #include <qbuttongroup.h> #include <qradiobutton.h> #include <qlistbox.h> #include <qtabdialog.h> #include <qtabbar.h> #include <qpushbutton.h> #include <qcolordialog.h> QString staedte[] = { "Sydney", const uint QString "Portland", "Austra-City", "Melbourne", "New London", "Manchester", "Kapstadt", "Canberra", "Jail-City", "Downunder-City" }; staedte_zahl "Koala-Town", "Suncity", = sizeof(staedte) / sizeof(staedte[0]); viertel_text[] = { "250000", "4000000", "2000000", "400000", "2500000" }; const uint viertel_zahl = sizeof(viertel_text) / sizeof(viertel_text[0]); //........................................................... Klasse TabDialog class TabDialog : public QTabDialog { Q_OBJECT public: TabDialog( QString h, QString v, QString p, QColor f, QWidget *parent = 0, const char *name = 0 ) : QTabDialog( parent, name ) { // // // .... Zum Aendern des Stils der Tableiste (in folg. Zeile // entfernen) QTabBar *tb = new QTabBar( this ); .... Verschiedene Stilarten (in folg. 4 Zeilen ein // entfernen) // tb->setShape( QTabBar::RoundedAbove ); // tb->setShape( QTabBar::RoundedBelow ); // tb->setShape( QTabBar::TriangularAbove ); // // tb->setShape( QTabBar::TriangularBelow ); .... Zum Aendern des Stils der Tableiste (in folg. Zeile // entfernen) 451 6 Vordefinierte Dialogfenster // setTabBar( tb ); hauptstadt = h; viertel = v; preis = p; farbe = f; setupTab1(); setupTab2(); setupTab3(); setzeAlt(); setApplyButton( "Übernehmen" ); setOkButton(); setCancelButton( "Abbrechen" ); setDefaultButton( "Voreinstellung" ); connect( this, SIGNAL( applyButtonPressed() ), SLOT( setzeUebernehmen() ) ); connect( this, SIGNAL( defaultButtonPressed() ), SLOT( setzeDefault() ) ); } QString getHauptstadt() { return hauptstadt; } QString getViertel() { return viertel; QString getPreis() { return preis; } QColor { return farbe; } getFarbe() } signals: void neuUebernommen(); private slots: void setzeUebernehmen() { uint //...................... setzeUebernehmen i; hauptstadt = viertel = ""; for (i=0; i<cities->count(); i++) if ( cities->isSelected( i ) ) hauptstadt = cities->text( i ); for (i=0; i<viertel_zahl; i++) if ( frage2a[i]->isChecked() ) viertel = frage2a[i]->text(); preis = frage2b->text(); farbe = neuFarbe; emit neuUebernommen(); } void setzeDefault() { //............... setzeDefault uint i; cities->clear(); for ( i = 0; i < staedte_zahl; i++ ) cities->insertItem( staedte[i], i ); for ( i=0; i<viertel_zahl; i++) frage2a[i]->setChecked( false ); frage2b->setText( "" ); farbAnzeige->setPalette( QPalette( neuFarbe=Qt::white, Qt::white ) ); } void neueFarbe() { //........................ neueFarbe QColor f = QColorDialog::getColor( neuFarbe, 0 ); if ( f.isValid() ) farbAnzeige->setPalette( QPalette( neuFarbe = f, f ) ); } private: QListBox *cities; QRadioButton *frage2a[viertel_zahl]; QLineEdit 452 *frage2b; 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat QLabel *farbAnzeige; QPushButton *farbButton; QString hauptstadt, viertel, preis; QColor farbe, neuFarbe; void setupTab1(); void setupTab2(); void setupTab3(); void setzeAlt() { uint //........................ setzeAlt i; for ( i=0; i < cities->count(); i++ ) cities->setSelected( i, cities->text(i) == hauptstadt ); for ( i=0; i<viertel_zahl; i++) frage2a[i]->setChecked( viertel == frage2a[i]->text() ); frage2b->setText( preis ); farbAnzeige->setPalette( QPalette( neuFarbe = farbe, farbe ) ); } }; //.................................................................. setupTab1 void TabDialog::setupTab1() { QVBox *tab1 = new QVBox( this ); tab1->setMargin( 5 ); tab1->setSpacing( 5 ); QLabel *l = new QLabel( "Wie heisst die Hauptstadt von Australien?", tab1 ); l->setBackgroundColor( Qt::yellow ); cities = new QListBox( tab1 ); for ( uint i = 0; i < staedte_zahl; i++ ) cities->insertItem( staedte[i], i ); cities->setPalette( QPalette( Qt::green, Qt::green ) ); addTab( tab1, "Allgemeinwissen" ); } //.................................................................. setupTab2 void TabDialog::setupTab2() { QVBox *tab2 = new QVBox( this ); tab2->setMargin( 5 ); tab2->setSpacing( 5 ); QButtonGroup *bg = new QButtonGroup( 1, QGroupBox::Horizontal, "Wieviel ist eine Million geteilt durch ein Viertel?", tab2 ); for (uint i=0; i<viertel_zahl; i++) { frage2a[i] = new QRadioButton( viertel_text[i], bg ); frage2a[i]->setBackgroundColor( Qt::green.light( 180 ) ); } bg->setBackgroundColor( Qt::green.light( 180 ) ); bg->setMinimumHeight( 200 ); QLabel *l = new QLabel( tab2 ); l->setText( "Eine Flasche Wein kostet zehn Euro,\n" "Der Wein kostet acht Euro mehr als die Flasche.\n" "Wie teuer ist die Flasche?" ); l->setBackgroundColor( Qt::yellow ); 453 6 Vordefinierte Dialogfenster frage2b = new QLineEdit( tab2 ); addTab( tab2, "Mathematik" ); } //.................................................................. setupTab3 void TabDialog::setupTab3() { QVBox *tab3 = new QVBox( this ); tab3->setMargin( 50 ); tab3->setSpacing( 30 ); farbButton = new QPushButton( "Farbauswahl", tab3 ); connect( farbButton, SIGNAL( clicked() ), SLOT( neueFarbe() ) ); farbAnzeige = new QLabel( tab3 ); addTab( tab3, "Farben" ); } //............................................................ Klasse MyWidget class MyWidget : public QVBox { Q_OBJECT public: MyWidget() : QVBox( 0, 0 ) { QPushButton *b1 = new QPushButton( "TabDialog", this); b1->setPalette( QPalette( Qt::green, Qt::green ) ); hauptstadt = viertel = preis = ""; farbe = Qt::white; auswahlAnzeige = new QLabel( this ); QString s; s.sprintf( " Hauptstadt: %s\n" " Eine Million geteilt durch ein Viertel: %s\n" " Preis der Flasche: %s\n" " Farbe (siehe Hintergrund)\n", (const char *)hauptstadt, (const char *)viertel, (const char *)preis ); auswahlAnzeige->setText( s ); auswahlAnzeige->setPalette( QPalette( farbe, farbe ) ); auswahlAnzeige->resize( auswahlAnzeige->sizeHint() ); auswahlAnzeige->setFixedSize( 400, 200 ); auswahlAnzeige->show(); QPushButton *b2 = new QPushButton( "Beenden", this); b2->setPalette( QPalette( Qt::red, Qt::red ) ); connect( b1, SIGNAL( clicked() ), this, SLOT( showTabDialog() ) ); connect( b2, SIGNAL( clicked() ), qApp, SLOT( quit() ) ); } private slots: void neuAnzeige() { QString s; hauptstadt = tabdialog->getHauptstadt(); viertel = tabdialog->getViertel(); preis = tabdialog->getPreis(); farbe = tabdialog->getFarbe(); s.sprintf( " Hauptstadt: %s (%s)\n" " Eine Million geteilt durch ein Viertel: %s (%s)\n" " Preis der Flasche: %s (%s)\n" " Farbe (siehe Hintergrund)\n", 454 6.6 Klasse QTabDialog zur Stapelung von Widgets im Karteikartenformat (const char *)hauptstadt, (hauptstadt=="Canberra") ? "Richtig" : "Falsch", (const char *)viertel, (viertel=="4000000") ? "Richtig" : "Falsch", (const char *)preis, (preis=="1") ? "Richtig" : "Falsch" ); auswahlAnzeige->setText( s ); auswahlAnzeige->setPalette( QPalette( farbe, farbe ) ); repaint(); } void showTabDialog() { tabdialog = new TabDialog( hauptstadt, viertel, preis, farbe ); tabdialog->resize( 450, 500 ); tabdialog->setCaption( "Wissenstest mit Farbenwahl" ); tabdialog->show(); connect( tabdialog, SIGNAL( neuUebernommen() ), this, SLOT( neuAnzeige() ) ); } private: TabDialog *tabdialog; QLabel *auswahlAnzeige; QString hauptstadt, viertel, preis; QColor farbe; }; //....................................................................... main int main( int argc, char *argv[] ) { QApplication a( argc, argv ); MyWidget *w = new MyWidget; w->resize( 200, 100 ); w->show(); a.setMainWidget( w ); return a.exec(); } #include "tabdialog.moc" Abbildung 6.21: Seite 1 zur Eingabe des Namens und der Adresse 455 Index Symbole Überlappendes Layout . . 399 Übung ampeltimer.cpp . . . 637 autofahr.cpp . . . . . . . 88 bildflow.cpp . . . . . . 416 canvas2.cpp . . . . . . . . 745 clipboardsend.cpp . . . 598 clipping2.cpp . . . . . 711 colordialog2.cpp . 423 countrydate.cpp . . 954 cursor2.cpp . . . . . . . . 759 customevent3.cpp . 867 datapump2.cpp . . . . 1025 datastream2.cpp . . 504 dezahexa.cpp . . . . . . . 82 dialog2.cpp . . . . . . . . 420 domplot2.cpp . . . . . 1077 dragdropcards.cpp . . . 615 dualstack.cpp . . . . . 586 dynfokus.cpp . . . . . . 820 dynlayout.cpp . . . . . 397 dynvalidator.cpp . 799 editor.cpp . . . . . . . . . 289 ehe.cpp . . . . . . . . . . . . . 103 eventfilter2.cpp . 858 filebytes.cpp . . . . . 492 filedialog2.cpp . . 431 flywindow.cpp . . . . . 727 fontdialog2.cpp . . 436 frame2.cpp . . . . . . . . . 358 functionplot2.cpp . . . 898 glpyramide.cpp . . 1084 graphik2.cpp . . . . . . . 82 graphik2.h . . . . . . . . . . 82 groupbox2.cpp . . . . . 363 httpd3.cpp . . . . . . . . 1019 image2.cpp . . . . . . . . . 770 inputdialog2.cpp . 483 josephus.cpp . . . . . . 582 lcdwandel2.cpp . . . 254 life.cpp . . . . . . . . . . . . 675 linkreis.cpp . . . . . . 691 listbox.cpp . . . . . . . . 223 listview2.cpp . . . . . 312 logging.cpp . . . . . . . . 961 lspin.cpp . . . . . . . . . . 235 manntisch.cpp . . . . . 668 mastermind.cpp . . . 377 meinls.cpp . . . . . . . . . 513 menues2.cpp . . . . . . . . 264 messagebox2.cpp . . 445 movieframes.cpp . . 785 multidownload.cpp . . . 984 multtable.cpp . . . . . 350 nsbillard.cpp . . . . 1114 ostern.cpp . . . . . . . . . 622 paintstack.cpp . . . 716 penfill.cpp . . . . . . . . 655 perl_listspin . . . . 1096 perl_malprog3 . . . . 1096 coverview.cpp . . . . . 915 pointarray2.cpp . . 547 printbild2.cpp . . . 476 progressbar2.cpp . 300 progressdialog2.cpp . . . . . . . . . 301 pythagoras.cpp . . . 705 queue.cpp . . . . . . . . . . . 58 queue2.cpp . . . . . . . . . 591 radioadd.cpp . . . . . . 879 regexp4.cpp . . . . . . . . 811 restaurant.cpp . . . 942 scrollview2.cpp . . 333 sendevent2.cpp . . . 862 snapshot2.cpp . . . . . 754 sound2.cpp . . . . . . . . . 788 splitter2.cpp . . . . . 369 tabdialog2.cpp . . . 456 timeprogress.cpp . 628 togglebutton.cpp . 216 virtfrank.cpp . . . . . . 88 waldbrand.cpp . . . . . 669 wellen.cpp . . . . . . . . . 668 widgetstack2.cpp . 373 wizard2.cpp . . . . . . . . 462 woist.cpp . . . . . . . . . . 520 woistmaus.cpp . . . . . 246 worktime.cpp . . . . . . 630 xmlplot2.cpp . . . . . 1077 xref.cpp . . . . . . . . . . . . 566 zeilzeich.cpp . . . . . 490 zeilzeich2.cpp . . . 497 zweirect.cpp . . . . . . 530 A Animation . . . . . . . . . 733, 775 ASSERT Makro . . . . . . . . . 957 Austritts-Events . . . . . . . . 847 Auswahlwidgets . . . . . . . . 216 B Balloon help . . . . . . . . . . . . 271 Bedingungs-Variablen . . 937 Benutzerdefinierte Events . . . 862 Benutzerdefiniertes Layout . 398 Beschleuniger . . . . . . . . . . . 258 Bildformate . . . . . . . . . . . . . 747 Browser . . . . . . . . . . . . . . . . 236 Directory . . . . . . . . . . . . . 308 Bubble help . . . . . . . . . . . . . 271 Buttongruppe . . . . . . . . . . . 363 Buttons . . . . . . . . . . . . . . . . . 204 C C++ . . . . . . . . . . . . . . . . . . . . . . 11 << . . . . . . . . . . . . . . . . . . . . . 27 >> . . . . . . . . . . . . . . . . . . . . . 27 1155 Index Überladen von Funktionen 18 Zeilen-Kommentar // . 16 Abstrakte Klassen . . . . . 89 cerr . . . . . . . . . . . . . . . . . . 27 cin . . . . . . . . . . . . . . . . . . . . 27 clog . . . . . . . . . . . . . . . . . . 27 cout . . . . . . . . . . . . . . . . . . 27 Default-Argumente . . . . 17 delete . . . . . . . . . . . . . . . 36 Destruktor . . . . . . . . . . . . . 48 Frühe Bindung . . . . . . . . 83 friend . . . . . . . . . . . . . . . 65 Function overloading . . 18 Inline-Funktionen . . . . . 19 Klassen . . . . . . . . . . . . . . . . 55 Mehrfachvererbung . . . . 98 Methoden . . . . . . . . . . . . . 38 new . . . . . . . . . . . . . . . . . . . . 35 Nicht-objektorientierte Erweiterungen . . . . . . . 16 operator . . . . . . . . . . . . . 67 Operator overloading . . 65 Polymorphismus . . . . . . 92 private . . . . . . . . . . . . . . 42 protected . . . . . . . . . . . 42 public . . . . . . . . . . . . . . . 42 Referenz-Operator & . . . 20 Späte Bindung . . . . . . . . . 86 Strukturen . . . . . . . . . . . . . 37 TemplateFunktionen . . . . . . . . . . . . 110 Klassen . . . . . . . . . . . . . . . . 105 this . . . . . . . . . . . . . . . . . . 40 C++ Variablen-Deklarationen 16 Vererbung . . . . . . . . . . . . . 72 Virtuelle Basisklassen . . . . . . . . . . . 100 Methoden . . . . . . . . . . . . . . 86 CHECK_PTR Makro . . . . . 957 Clipboard . . . . . . . . . . . . . . 593 mit Drag-and-Drop . . . 607 Clipping (Graphik) . . . . . 708 Close-Events . . . . . . . . . . . . 849 ColorRole Typ . . . . . . . . 149 connect() . . . . . . . . . . . . . . . 130 connect() . . . . . . . . . . . . 869 Containerklasse QList . . . . . . . . . . . . . . . . 567 Hashtabelle . . . . . . . . . . . 547 Listen . . . . . . . . . . . . . . . . 567 QArray . . . . . . . . . . . . . . 535 QAsciiCache . . . . . . . . 562 QAsciiDict . . . . . . . . . 557 QBitArray . . . . . . . . . . 540 1156 QByteArray . . . . . . . . . 540 QCache . . . . . . . . . . . . . . 559 QDict . . . . . . . . . . . . . . . . 547 QIntCache . . . . . . . . . . 562 QIntDict . . . . . . . . . . . . 557 QMap . . . . . . . . . . . . . . . . . 563 QPointArray . . . . . . . . 543 QPtrDict . . . . . . . . . . . . 557 QQueue . . . . . . . . . . . . . . 587 QStack . . . . . . . . . . . . . . 582 QStrIList . . . . . . . . . . 580 QStringList . . . . . . . . 577 QStrList . . . . . . . . . . . . 580 QValueList . . . . . . . . . 573 QValueStack . . . . . . . . 584 QVector . . . . . . . . . . . . . 540 Containerklassen . . . . . . . 521 critical() . . . . . . . . . . . 171 Cursorformen . . . . . . 747, 754 D Danksagung . . . . . . . . . . . . Data-Sharing . . . . . . . . . . . Dateiauswahl-Dialogbox Dateioperationen . . . . . . . Datenstruktur QList . . . . . . . . . . . . . . . . FIFO . . . . . . . . . . . . . . . . . Hashtabelle . . . . . . . . . . . LIFO . . . . . . . . . . . . . . . . . Listen . . . . . . . . . . . . . . . . QArray . . . . . . . . . . . . . . QAsciiCache . . . . . . . . QAsciiDict . . . . . . . . . QBitArray . . . . . . . . . . QByteArray . . . . . . . . . QCache . . . . . . . . . . . . . . QDict . . . . . . . . . . . . . . . . QIntCache . . . . . . . . . . QIntDict . . . . . . . . . . . . QMap . . . . . . . . . . . . . . . . . QPointArray . . . . . . . . QPtrDict . . . . . . . . . . . . QQueue . . . . . . . . . . . . . . QStack . . . . . . . . . . . . . . Queue . . . . . . . . . . . . . . . . QValueList . . . . . . . . . QValueStack . . . . . . . . QVector . . . . . . . . . . . . . Stack . . . . . . . . . . . . . . . . . Warteschlange . . . . . . . . Datenstrukturen . . . . . . . . Datentypen . . . . . . . . . . . . . Datum . . . . . . . . . . . . . . . . . . Datum und Zeit . . . . . . . . Debugging . . . . . . . . . . . . . VII 530 424 485 567 587 547 582 567 535 562 557 540 540 559 547 562 557 563 543 557 587 582 587 573 584 540 582 587 521 521 617 628 955 deep copy-Sharing . . . . . . 532 Dialogbox . . . . . . . . . . . . . . 417 Dateiauswahl . . . . . . . . . 424 Drucker . . . . . . . . . . . . . . 463 Einfache Eingabe . . . . . 477 Farbe . . . . . . . . . . . . . . . . . 421 Font . . . . . . . . . . . . . . . . . . 432 Fortschrittsanzeige . . . 294, 483 Karteikarten . . . . . . . . . . 446 Kombobox-Eingabe . . . 477 Message . . . . . . . . . . . . . . 436 Mitteilungen . . . . . . . . . 436 Nachrichten . . . . . . . . . . 436 Tabdialog . . . . . . . . . . . . . 446 Texteingabe . . . . . . . . . . . 477 Wizards . . . . . . . . . . . . . . 456 Zahleneingabe . . . . . . . . 477 Dialogfenster . . . . . . . . . . . 417 Directorybrowser . . . . . . . 308 Directoryoperationen . . 485, 513 Dokumentation . . . . . . . . . 117 DOM-Schnittstelle . . . . . 1053 Doppel-Pufferung . . . . . . 719 Drag-and-Drop . . . . . . . . . 598 MIME-Typen . . . . . . . . . 609 mit Clipboard . . . . . . . . 607 Drag-Events . . . . . . . . 599, 854 Drehknopf . . . . . . . . . . . . . . 225 Drop-Events . . . . . . . 599, 854 Druckerdialog . . . . . . . . . . 463 Druckerinformationen . . 466 dumpObjectInfo Funktion 959 dumpObjectTree Funktion 959 Dynamisch änderndes Layout . . . . . . . . . . . . . 403 E E/A-Geräte . . . . . . . . . . . . . 485 Ebuilder . . . . . . . . . . . . . . . 1142 Editor einzeilig . . . . . . . . . . . . . . 246 mehrzeilig . . . . . . . . . . . . 247 Einfaches Layout . . . . . . . 374 Eintritts-Events . . . . . . . . . 847 Ereignisse . . . . . . . . . . . . . . 823 Event Austritts- . . . . . . . . . . . . . 847 Benutzerdefiniert . . . . . 862 Close- . . . . . . . . . . . . . . . . 849 Custom- . . . . . . . . . . . . . . 862 Drag- . . . . . . . . . . . . 599, 854 Drop- . . . . . . . . . . . . 599, 854 Index Eintritts- . . . . . . . . . . . . . . 847 Fokus- . . . . . . . . . . . . . . . . 841 Größenänderungs- . . . 843 Hide- . . . . . . . . . . . . . . . . . 848 Mal- . . . . . . . . . . . . . . . . . . 826 Maus- . . . . . . . . . . . . . . . . 827 Positionsänderungs- . . 845 Resize- . . . . . . . . . . . . . . . 843 Schließ- . . . . . . . . . . . . . . . 849 Senden . . . . . . . . . . . . . . . 858 Show- . . . . . . . . . . . . . . . . 849 Sichtbarkeits- . . . . . . . . . 849 Subwidget- . . . . . . . . . . . 852 Synthetisch . . . . . . . . . . . 858 Tastatur- . . . . . . . . . . . . . . 834 Timer- . . . . . . . . . . . 634, 840 Versteck- . . . . . . . . . . . . . 848 Event-Filter . . . . . . . . 823, 855 Events . . . . . . . . . . . . . . . . . . 823 Explizites Data-Sharing . 530 F Füllbalken . . . . . . . . . . . . . . 290 einfach . . . . . . . . . . . . . . . 290 Fortschrittsanzeige . . . 294 Farb-Dialogbox . . . . . . . . . 421 Farballozierung . . . . . . . . . 639 Farbgruppen in Qt . . . . . . 149 Farbmodelle in Qt . . . . . . 146 Farbname QColor-Objekte . . . . . . 148 vordefinierte Strings . . 148 Filter (Event) . . . . . . . 823, 855 findtr Tool . . . . . . . . . . . . 948 Flache Kopie . . . . . . . . . . . . 532 Flimmerfreie Graphik . . . 717 Fokus . . . . . . . . . . . . . . . . . . . 813 Fokus-Events . . . . . . . . . . . 841 Font-Dialogbox . . . . . . . . . 432 Form Cursor . . . . . . . . . . . . . . . . 747 Format Bilder . . . . . . . . . . . . . . . . 747 Pixmap . . . . . . . . . . . . . . . 747 Fortgeschrittenes Layout 377 Fortschrittsanzeige . . . . . . 483 Fortschrittsanzeige Klasse . . 294 Frames . . . . . . . . . . . . . . . . . 352 FTP Protokoll . . . . . . . . . . . 992 Funktionsplotter . . . . . . . . 882 G Geleitwort . . . . . . . . . . . . . . . . V Geschachteltes Layout . . 386 getOpenFileName() . 197 getSaveFileName() . 196 Größenänderungs-Events . . . 843 Graphik . . . . . . . . . . . . . . . . 639 Clipping . . . . . . . . . . . . . . 708 Doppel-Pufferung . . . . 719 Füllmuster . . . . . . . . . . . . 652 Flimmerfrei . . . . . . . . . . . 717 Geometrische Figuren 657, 670 Positionieren . . . . . . . . . 657 Rasterung . . . . . . . . . . . . 720 Text . . . . . . . . . . . . . . . . . . 660 Transformationen . . . . . 675 View-Transformationen . . . 692 Graphik Viewport-Transformationen 698 Graphik Window-Transformationen 692 Graphik World-Transformationen . . . 675 Zeichenstift . . . . . . . . . . . 650 Gruppenboxen . . . . . . . . . 358 GUI-Builder . . . . . . . . . . . 1117 Ebuilder . . . . . . . . . . . . . 1142 Qt-Designer . . . . . . . . . 1117 QtArchitect . . . . . . . . . . 1142 QtEz . . . . . . . . . . . . . . . . 1142 H Hashtabellen . . . . . . . . . . . Hauptfenster . . . . . . . . . . . Hide-Events . . . . . . . . . . . . High-Level Events . . . . . . Hilfstexte . . . . . . . . . . . . . . . HSV-Farbmodell . . . . . . . . HTML . . . . . . . . . . . . . . . . . . http Protokoll . . . . . . . . . . . 547 265 848 160 271 147 236 997 I Implizites Data-Sharing . 530 information() . . . . . . . 171 Informationswidgets . . . . 235 Internationalisierung . . . 943 Iterator QAsciiCacheIterator . 562 QAsciiDictIterator . . 557 QCacheIterator . . . 561 QDictIterator . . . . . 552 QIntCacheIterator . . . 562 QIntDictIterator . 557 QListIterator . . . . . 571 QMapConstIterator . . . 566 QMapIterator . . . . . . 566 QPtrDictIterator . 557 QValueListConstIterator 575 QValueListIterator . . 575 K Karteikarten . . . . . . . . . . . . Komboboxen . . . . . . . . . . . Kompilieren Qt-Programme . . . . . . . Konsistente Eingaben . . . Kopie flache . . . . . . . . . . . . . . . . . tiefe . . . . . . . . . . . . . . . . . . 446 218 119 790 532 532 L Labels . . . . . . . . . . . . . . . . . . Laufbalken . . . . . . . . . . . . . Layout . . . . . . . . . . . . . . . . . . Überlappend . . . . . . . . . Benutzerdefiniert . . . . . Dynamisch ändernd . . Einfach . . . . . . . . . . . . . . . Fortgeschritten . . . . . . . Geschachtelt . . . . . . . . . . Tabellenform . . . . . . . . . LCD-Anzeige . . . . . . . . . . . linguist Tool . . . . . . . . . Listboxen . . . . . . . . . . . . . . . Listenansicht . . . . . . . . . . . Low-Level Events . . . . . . . lrelease Tool . . . . . . . . . lupdate Tool . . . . . . . . . . 235 312 373 399 398 403 374 377 386 389 237 947 216 302 160 948 945 M Mainwindow . . . . . . . . . . . 264 make Tool . . . . . . . . . 120, 1149 Makefile . . . . . . . . . . . . . . . 1149 Mal-Events . . . . . . . . . . . . . 826 Maus-Events . . . . . . . . . . . 827 Mauscursor . . . . . . . . . . . . . 754 Mehrsprachige Applikationen . . . . . . 943 Menüleiste . . . . . . . . . . . . . . 259 Menüs . . . . . . . . . . . . . . . . . . 254 Kontext . . . . . . . . . . . . . . . 259 Popup . . . . . . . . . . . . . . . . 259 mergetr Tool . . . . . . . . . . 948 Messagebox . . . . . . . . . . . . 436 Meta Object Compiler . siehe moc 1157 Index MIME-Typen . . . . . . . . . . . 609 moc . . . . . . . . . . . . . . . . . . . . . 134 mouseDoubleClickEvent() 166 msg2qm Tool . . . . . . . . . . . . 948 Mutual Exclusion . . . . . . . 922 N Namen von Objekten . . . 959 Netscape Plugins . . . . . . 1096 Netzwerkprogrammierung . 965 nntp Protokoll . . . . . . . . . 1000 O Objektnamen . . . . . . . . . . . 959 Objektorientierung . . . . . . . 11 Attribute . . . . . . . . . . . . . . 55 Basisklasse . . . . . . . . . . . . 55 Exemplar . . . . . . . . . . . . . . 55 Instanz . . . . . . . . . . . . . . . . 55 Methode . . . . . . . . . . . . . . . 55 Objekt . . . . . . . . . . . . . . . . . 55 Operation . . . . . . . . . . . . . 55 Vererbung . . . . . . . . . . . . . 55 Online-Dokumentation . 117 Online-Hilfe . . . . . . . . . . . . 271 OpenGL . . . . . . . . . . . . . . . 1079 P Paletten in Qt . . . . . . . . . . . 150 PerlQt . . . . . . . . . . . . . . . . . 1085 Pixmap-Format . . . . . . . . . 747 Plotter . . . . . . . . . . . . . . . . . . 882 Plugins . . . . . . . . . . . . . . . . 1096 Popupmenü . . . . . . . . . . . . 213 Positionsänderungs-Events . 845 progen Tool . . . . . . . . . . . 1154 Programm dragdropclip.cpp . 608 alt_ea.cpp . . . . . . . . . . 26 ampel.cpp . . . . . . . . . . 940 ampeltimer.cpp . . . 637 analoguhr.cpp . . . . . 689 array.cpp . . . . . . . . . . 538 array2.cpp . . . . . . . . . 539 auswahlw.cpp . . . . . . 219 autofahr.cpp . . . . . . . 88 bildflow.cpp . . . . . . 416 bildformat.cpp . . . 605 bildtabelle.cpp . . 901 bildtabelle.h . . . . . 900 biszeit.cpp . . . . . . . . 630 bitarray.cpp . . . . . . 542 bitblt.cpp . . . . . . . . . 722 bitblt2.cpp . . . . . . . . 725 1158 bruch.cpp . . . . . . . . . . . 62 bruch.h . . . . . . . . . . . . . . 61 bruchio.cpp . . . . . . . . . 63 bruchio.h . . . . . . . . . . . 63 bruchrec.cpp . . . . . . . 43 bruchtyp.cpp . . . . . . . 65 bruchtyp2.cpp . . . . . . 70 button_gruppe.cpp 211 button_popup.cpp . 213 button_slot.cpp . . 874 buttons.cpp . . . . . . . . 208 canvas.cpp . . . . . . . . . 742 canvas.h . . . . . . . . . . . . 737 childevent.cpp . . . 853 cinget.cpp . . . . . . . . . . 33 cinget2.cpp . . . . . . . . . 35 cingetline.cpp . . . . . 34 cinstring.cpp . . . . . . 33 clipboardimage.cpp . . 596 clipboardsend.cpp . . . 598 clipboardtext.cpp . . . 595 clipping.cpp . . . . . . 709 colordialog.cpp . . 422 colordialog2.cpp . 423 cqueue.cpp . . . . . . . . . . 59 cstack.cpp . . . . . . . . . . 56 cursor.cpp . . . . . . . . . 757 customevent.cpp . . 863 customevent2.cpp . 865 datapump.cpp . . . . . 1023 datastream.cpp . . . 502 datastream2.cpp . . 504 datediff.cpp . . . . . . 621 datum.cpp . . . . . . . . . . . 46 destruktor.cpp . . . . . 49 dezahexa.cpp . . . . . . . 82 dial.cpp . . . . . . . . . . . . 231 dialekt1.cpp . . . . . . . 84 dialog.cpp . . . . . . . . . 419 dialog2.cpp . . . . . . . . 420 dict.cpp . . . . . . . . . . . . 551 dict2.cpp . . . . . . . . . . 551 dictiterator.cpp . 553 DigitalClock.pm . 1095 digitaluhr.cpp . . . 633 digitaluhr2.cpp . . 635 dirbrows.cpp . . . . . . 309 dirbrows.h . . . . . . . . . 308 displaystdin.cpp 1008 dom1.cpp . . . . . . . . . . 1055 domplot.cpp . . . . . . 1072 doublevalidator.cpp . 798 download.cpp . . . . . . 982 dragdropcards.cpp . . . 615 dragdropimage.cpp . . . 602 dragdropmime.cpp . . . 612 dragdroptext.cpp . 600 drawutil.cpp . . . . . . 671 dualstack.cpp . . . . . 586 dumpobject.cpp . . . 959 dynlayout.cpp . . . . . 397 dynvalidator.cpp . 799 enterleave.cpp . . . 847 entferbi.cpp . . . . . . 144 eventfilter.cpp . . 857 farbe.cpp . . . . . . . . . . 153 farbgruppe.cpp . . . 156 farbmenu.cpp . . . . . . 257 figrotate.cpp . . . . . 712 filebytes.cpp . . . . . 492 filedialog.cpp . . . 427 filedialog2.cpp . . 431 fileinfo.cpp . . . . . . 508 filetransfer.cpp . 972 flowlayout.cpp . . . 406 flowlayout.h . . . . . . 405 focusevent.cpp . . . 842 fokus1.cpp . . . . . . . . . 815 fokus2.cpp . . . . . . . . . 819 fontdialog.cpp . . . 434 fontdialog2.cpp . . 436 frame.cpp . . . . . . . . . . 354 frame2.cpp . . . . . . . . . 358 functemplate.cpp . 112 functionparser.cpp . . 896 functionplot.cpp . 885 functionplot.h . . . 883 Generierung . . . . 120, 1149 glbox.cpp . . . . . . . . . 1081 globlok.cpp . . . . . . . . . 50 graphik.cpp . . . . . . . . . 79 graphik.h . . . . . . . . . . . 77 groupbox.cpp . . . . . . 360 groupbox2.cpp . . . . . 363 hai.cpp . . . . . . . . . . . . . 102 hauptfenster.cpp . 268 hexd.cpp . . . . . . . . . . . . 501 http.cpp . . . . . . . . . . . . 997 httpd2.cpp . . . . . . . . 1012 huhn.cpp . . . . . . . . . . . . 648 ignore.cpp . . . . . . . . . . 32 image.cpp . . . . . . . . . . 765 inline.cpp . . . . . . . . . . 20 inputdialog.cpp . . 480 inputdialog2.cpp . 483 Index intdict.cpp . . . . . . . . 558 intdict2.cpp . . . . . . 559 international.cpp . . . 949 intvalidator.cpp . 795 josephus.cpp . . . . . . 582 katzmaus.cpp . . . . . . 649 kehrzahl.cpp . . . . . . 145 keyevent.cpp . . . . . . 836 keyevent2.cpp . . . . . 839 klasstemplate.cpp . . . 109 kompilieren . . . . . . . . . . 119 layout1.cpp . . . . . . . . 375 layout2.cpp . . . . . . . . 381 layout3.cpp . . . . . . . . 382 layout4.cpp . . . . . . . . 383 layout5.cpp . . . . . . . . 385 layout6.cpp . . . . . . . . 387 layout7.cpp . . . . . . . . 392 layout8.cpp . . . . . . . . 394 lcdwandel.cpp . . . . . 243 lightdark.cpp . . . . . 152 lineedit.cpp . . . . . . 251 list.cpp . . . . . . . . . . . . 570 listiterator.cpp . 572 listspin.cpp . . . . . . 229 listview1.cpp . . . . . 306 machebi.cpp . . . . . . . . 143 main.cpp . . . . . . . . . . . . . 64 maintextsize.cpp 1124 maintextsize2.cpp . . . 1129 mainwindow.cpp . . . 284 makexmlfunction.c . . . 1047 malprog1.cpp . . . . . . 160 malprog2.cpp . . . . . . 165 malprog3.cpp . . . . . . 167 malprog4.cpp . . . . . . 173 malprog5.cpp . . . . . . 179 malprog6.cpp . . . . . . 189 map.cpp . . . . . . . . . . . . . 565 mastermind.cpp . . . 377 mehrerb1.cpp . . . . . . . 99 meinls.cpp . . . . . . . . . 513 memory.cpp . . . . . . . . . 904 menues.cpp . . . . . . . . . 261 messagebox.cpp . . . 441 messagebox2.cpp . . 445 mouseevent.cpp . . . 831 moveevent.cpp . . . . . 846 movies.cpp . . . . . . . . . 778 movies2.cpp . . . . . . . . 783 mutex.cpp . . . . . . . . . . 922 mutex2.cpp . . . . . . . . . 925 mymail.cpp . . . . . . . . 1015 networkprotocl.cpp . . 1000 neu_ea1.cpp . . . . . . . . . 26 neu_ea2.cpp . . . . . . . . . 28 neu_ea3.cpp . . . . . . . . . 28 neu_ea4.cpp . . . . . . . . . 30 noflimmer1.cpp . . . 717 noflimmer2.cpp . . . 719 noflimmer3.cpp . . . 723 noignore.cpp . . . . . . . 32 nsgifscale.cpp . . . 1112 nsgrep.cpp . . . . . . . . 1106 nsgrep.pl . . . . . . . . . 1110 nsplugin1.cpp . . . . 1102 numausg.cpp . . . . . . . . . 490 numausg2.cpp . . . . . . 496 oel.cpp . . . . . . . . . . . . . 644 ostern.cpp . . . . . . . . . 622 overlayout.cpp . . . 400 overlayout.h . . . . . . 399 overload.cpp . . . . . . . 19 painter.cpp . . . . . . . . 653 painter2.cpp . . . . . . 662 parser.cpp . . . . . . . . . 892 parser.h . . . . . . . . . . . . 891 perl_dclock . . . . . . 1094 perllcd_wandel . . 1092 perltext_groes . . 1086 philosophen.cpp . . 934 picture.cpp . . . . . . . . 771 pointarray.cpp . . . 545 pointarray2.cpp . . 547 poker.cpp . . . . . . . . . . 910 postistda.cpp . . . . . 511 potenz.cpp . . . . . . . . . 249 printbild.cpp . . . . . 473 printbild2.cpp . . . 476 printer1.cpp . . . . . . 466 printerinfo.cpp . . 467 printtext.cpp . . . . . 469 printviel.cpp . . . . . 475 progressbar.cpp . . 291 progressdialog.cpp . . 296 puzzle.cpp . . . . . . . . . 906 queue.cpp . . . . . . . . . . 588 queue2.cpp . . . . . . . . . 591 rahmenlayout.cpp . 411 rahmenlayout.h . . . 409 readerwriter.cpp . 929 reaktest.cpp . . . . . . 627 refarray.cpp . . . . . . . 24 regexp1.cpp . . . . . . . . 804 regexp2.cpp . . . . . . . . 807 regexp3.cpp . . . . . . . . 809 regexp4.cpp . . . . . . . . 811 rennen.cpp . . . . . . . . . 920 resizeevent.cpp . . 844 richtext.cpp 239, 1075 schachbrett.cpp . . 693 schachbrett2.cpp . 699 schieb_balk.cpp . . . . . . 129 scrollbar.cpp . . . . . 329 scrollbar.h . . . . . . . . 327 scrollview.cpp . . . 322 sendevent.cpp . . . . . 860 setviewport.cpp . . 700 showhideclose.cpp . . . 850 signal.cpp . . . . . . . . . 878 signalmapper.cpp . 876 sinus.cpp . . . . . . . . . . 695 sinusfunc.cpp . . . . . 888 snapshot.cpp . . . . . . 752 sound.cpp . . . . . . . . . . 787 spiro.cpp . . . . . . . . . . 696 splitter.cpp . . . . . . 367 splitter2.cpp . . . . . 369 stack.cpp . . . . . . . . . . 583 stringlist.cpp . . . 579 strlist.cpp . . . . . . . . 581 superhirn.cpp . . . . . . 52 tabdialog.cpp . . . . . 451 tabdialog2.cpp . . . 456 table.cpp . . . . . . . . . . 347 tableview . . . . . . . . . . 338 tableview.h . . . . . . . . 336 tausch.cpp . . . . . . . . . . 23 text_groes.cpp . . . 132 textsizeimpl.cpp . . . . . 1129, 1131 textsizeimpl.h . . 1129 thread.cpp . . . . . . . . . 918 tier.cpp . . . . . . . . . . . . . 91 tier.h . . . . . . . . . . . . . . . 90 timeprogress.cpp . 628 tooltip.cpp . . . . . . . . 272 tooltip2.cpp . . . . . . 276 transform.cpp . . . . . 680 treesize.cpp . . . . . . 519 validator.cpp . . . . . 792 valuelist.cpp . . . . . 577 valuestack.cpp . . . 585 virtfrank.cpp . . . . . . 89 welchtag.cpp . . . . . . 620 widgetstack.cpp . . 371 widgetstack2.cpp . 373 wizard.cpp . . . . . . . . . 458 wizard2.cpp . . . . . . . . 462 woist.cpp . . . . . . . . . . 520 worktime.cpp . . . . . . 630 1159 Index wortstat.cpp . . . . . . 555 xform.cpp . . . . . . . . . . 685 xml1.cpp . . . . . . . . . . 1029 xmlplot.cpp . . . . . . 1043 xmlrichtext.cpp . 1050 xref.cpp . . . . . . . . . . . . 566 zeigbild.cpp . . . . . . 238 zeilzeich.cpp . . . . . 490 zeilzeich2.cpp . . . 497 zeitadd.cpp . . . . . . . . 625 zoo.cpp . . . . . . . . . . . . . . 93 zoo.h . . . . . . . . . . . . . . . . . 93 zwei_buttons.cpp . 124 zweirect.cpp . . . . . . 530 Protokoll FTP . . . . . . . . . . . . . . . . . . 992 http . . . . . . . . . . . . . . . . . . 997 nntp . . . . . . . . . . . . . . . . . 1000 Q QApplication Klasse . 125 QArray Klasse . . . . . . . . . 535 QAsciiCache Klasse . . . 562 QAsciiCacheIterator Klasse . . . . . . . . . . . . . . 562 QAsciiDict Klasse . . . . 557 QAsciiDictIterator Klasse . . . . . . . . . . . . . . 557 QBitArray Klasse . . . . . 540 QBitmap Klasse . . . . . . . . 751 QBitVal Klasse . . . . . . . . 541 QBoxLayout Klasse . . . . 378 QBrush Klasse . . . . . . . . . 652 QBuffer Klasse . . . . . . . . 491 QButtonGroup Klasse . 873 QButtonGroup Klasse . 206, 363 QByteArray Klasse . . . . 540 QCache Klasse . . . . . . . . . 559 QCacheIterator Klasse . . . 561 QCanvas Klasse . . . . . . . . 727 QCanvasPolygonalItem Klasse . . . . . . . . . . . . . . 733 QCanvasEllipse Klasse . . . 732 QCanvasItem Klasse . . . 729 QCanvasLine Klasse . . . 731 QCanvasPixmap Klasse 734 QCanvasPixmapArray Klasse . . . . . . . . . . . . . . 735 QCanvasPolygon Klasse . . . 732 QCanvasRectangle Klasse 731 QCanvasSprite Klasse 733 1160 QCanvasText Klasse . . . 734 QCanvasView Klasse . . . 735 QChar Klasse . . . . . . . . . . . 137 QCheckBox Klasse . . . . . 205 QChildEvent Klasse . . . 853 QClipboard Klasse . . . . 594 QCloseEvent Klasse . . . 849 QColor Klasse . . . . . 146, 639 QColor-Objekte (vordefiniert) . . . . . . . 148 QColorDialog Klasse . 421 QColorDrag Klasse . . . . 606 QColorGroup Klasse . . . 149 QComboBox Klasse . . . . . 218 QCString Klasse . . . . . . . 604 QCursor Klasse . . . . . . . . 754 QCustomEvent Klasse . 863 QDataPump Klasse . . . . 1023 QDataSink Klasse . . . . 1022 QDataSource Klasse . 1021 QDataStream Klasse . . . 498 QDate Klasse . . . . . . . . . . . 617 QDateTime Klasse . . . . . 628 qDebug Funktion . . . . . . . 955 QDial Klasse . . . . . . . . . . . 225 QDialog Klasse . . . . . . . . 418 QDict Klasse . . . . . . . . . . . 547 QDictIterator Klasse 552 QDir Klasse . . . . . . . . . . 513 QDns Klasse . . . . . . . . . . . 1009 QDomAttr Klasse . . . . . . 1063 QDomCDATASection Klasse 1066 QDomCharacterData Klasse . . . . . . . . . . . . . 1064 QDomComment Klasse . 1065 QDomDocument Klasse 1061 QDomDocumentFragment Klasse . . . . . . . . . . . . . 1067 QDomDocumentType Klasse 1067 QDomElement Klasse . 1062 QDomEntity Klasse . . . 1068 QDomEntityReference Klasse . . . . . . . . . . . . . 1068 QDomImplementation Klasse . . . . . . . . . . . . . 1070 QDomNamedNodeMap Klasse 1070 QDomNode Klasse . . . . . . 1057 QDomNodeList Klasse 1071 QDomNotation Klasse 1069 QDomProcessingInstruction Klasse . . . . . . . . . . . . . 1069 QDomText Klasse . . . . . . 1066 QDoubleValidator Klasse 796 QDragEnterEvent Klasse . 854 QDragEnterEvent Klasse . 607 QDragLeaveEvent Klasse . 855 QDragMoveEvent Klasse . . . 607, 855 QDragObject Klasse 603 QDropEvent Klasse 607, 855 QEucJpCodec Klasse . . . 954 QEucKrCodec Klasse . . . 954 QEvent Klasse . . . . . . . . . 824 qFatal Funktion . . . . . . . 956 QFile Klasse . . . . . . . . . . . 487 QFileDialog Klasse . . . 424 QFileIconProvider Klasse . . . . . . . . . . . . . . 427 QFileInfo Klasse . . . . . 506 QFileInfoList Klasse 516 QFileInfoListIterator Klasse . . . . . . . . . . . . . . 516 QFilePreview Klasse . 427 QFocusData Klasse . . . . 818 QFocusEvent Klasse . . . 841 QFont Klasse . . 127, 201, 432 QFontDialog Klasse . . . 432 QFontInfo Klasse . . . . . 534 QFontMetrics Klasse . 469, 534 QFrame Klasse . . . . . . . . . 352 QFtp Klasse . . . . . . . . . . . . 992 QGbkCodec Klasse . . . . . 954 QGLContext Klasse . . . 1080 QGLFormat Klasse . . . . 1081 QGLWidget Klasse . . . . 1080 QGrid Klasse . . . . . . . . . . . 374 QGridLayout Klasse . . . 389 QGroupBox Klasse . . . . . 358 QHBox Klasse . . . . . . . . . . . 374 QHBoxLayout Klasse . . . 378 QHeader Klasse . . . . . . . . 344 QHideEvent Klasse . . . . 848 QHostAddress Klasse 1008 QIconDrag Klasse . 603, 607 QIconDragItem Klasse 607 QIconSet Klasse . . 344, 534 QIconView Klasse . . . . . 607 QImage Klasse . . . . . . . . . 759 QImageDrag Klasse . . . . 604 QImageIO Klasse . . . . . . . 764 QInputDialog Klasse . 477 qInstallMsgHandler Funktion . . . . . . . . . . . 956 Index QIntCache Klasse . . . . . 562 QIntCacheIterator Klasse . . . . . . . . . . . . . . 562 QIntDict Klasse . . . . . . . 557 QIntDictIterator Klasse 557 QIntValidator Klasse 794 QIODevice Klasse . . . . . 485 QIODeviceSource Klasse . 1021 QJisCodec Klasse . . . . . 954 QKeyEvent Klasse . . . . . 834 QLabel Klasse . . . . . 127, 235 QLayoutItem Klasse . . 399, 404 QLayoutIterator Klasse . 399 QLCDNumber Klasse 129, 237 QLineEdit Klasse . . . . . 246 QList Klasse . . . . . . . . . . . 567 QListBox Klasse . . . . . . . 216 QListIterator Klasse 571 QListView Klasse . . . . . 302 QListViewItem Klasse 304 QListViewItemIterator Klasse . . . . . . . . . . . . . . 305 QLocalFs Klasse . . . . . . . 993 qm2ts Tool . . . . . . . . . . . . . 948 QMap Klasse . . . . . . . . . . . . 563 QMapConstIterator Klasse . . . . . . . . . . . . . . 566 QMapIterator Klasse . 566 QMenuBar Klasse . . . . . . . 169 QMenuData Klasse . 170, 255 QMessageBox Klasse . . 171, 436 QMotifStyle Klasse . . . 203 QMouseEvent Klasse . . . 828 QMoveEvent Klasse . . . . 845 QMovie Klasse . . . . . . . . . 775 QMultiLineEdit Klasse . . . 247 QMutex Klasse . . . . . . . . . 922 QNetworkOperation Klasse . . . . . . . . . . . . . . 978 QNetworkProtocol Klasse 984, 990 QNPInstance Klasse . 1099 QNPlugin Klasse . . . . . . 1097 QNPStream Klasse . . . . 1101 QNPWidget Klasse . . . . 1100 QObject Klasse . . . . . . . . 126 QObject Klasse . . . . . . . . 132 QPaintDeviceMetrics Klasse . . . . . . . . . . . . . . 466 QPainter Klasse . . . . . . . 639 QPainter-Zustand Sichern . . . . . . . . . . . . . . . 712 Wiederherstellen . . . . . 712 QPaintEvent Klasse . . . 827 QPalette Klasse . . . . . . . 150 QPen Klasse . . . . . . . . . . . . 650 QPicture Klasse . . . . . . . 770 QPixmap Klasse . . . . . . . . 748 QPixmapCache Klasse . 751 QPoint Klasse . . . . . . . . . 523 QPointArray Klasse 543 QPopupMenu Klasse . . . . 168 QPrinter Klasse . . . . . . . 463 QProgressBar Klasse . 290 QProgressDialog Klasse . 294, 483 QPtrDict Klasse . . . . . . . 557 QPtrDictIterator Klasse 557 QPushButton Klasse . . . 204 QQueue Klasse . . . . . . . . . 587 QRadioButton Klasse . 205 QRangeControl Klasse 225 QRect Klasse . . . . . . . . . . . 527 QRegExp Klasse . . . . . . . . 799 QRegion Klasse . . . . . . . . 708 QResizeEvent Klasse . 844 QRgb Klasse . . . . . . . . . . . . 421 QScrollBar Klasse . . . . 326 QScrollView Klasse . . 172, 312 QSemaphore Klasse . . . . 927 QSemiModal Klasse . . . . 294 QServerSocket Klasse 996 QShowEvent Klasse . . . . 849 QSignal Klasse . . . . . . . . 877 QSignalMapper Klasse 875 QSize Klasse . . . . . . . . . . . 525 QSjisCodec Klasse . . . . 954 QSlider Klasse . . . . 128, 224 QSocket Klasse . . . . . . . . 993 QSocketDevice Klasse 996 QSocketNotifier Klasse . 1005 QSound Klasse . . . . . . . . . 786 QSpinBox Klasse . . . . . . . 227 QSplitter Klasse . . . . . 363 QStack Klasse . . . . . . . . . 582 QStoredDrag Klasse . . . 615 QStoredDrag Klasse . . . 603 QStrIList Klasse . . . . . 580 QString Klasse . . . . . . . . 137 QStringList Klasse . . . 577 QStrList Klasse . . . . . . . 580 QStyle Klasse . . . . . . . . . 203 Qt-Designer . . . . . . . . . . . 1117 Qt-Referenz . . . . . . . . . . . . . 117 QTabDialog Klasse . . . . 446 QTable Klasse . . . . . . . . . 341 QTableItem Klasse . . . . 345 QTableSelection Klasse . 345 QTableView Klasse . . . . 333 QtArchitect . . . . . . . . . . . . 1142 QTextBrowser Klasse . 236 QTextCodec Klasse . . . . 954 QTextDrag Klasse . . . . . 604 QTextStream Klasse . . . 493 QTextView Klasse . . . . . 236 QtEz . . . . . . . . . . . . . . . . . . . 1142 QThread Klasse . . . . . . . . 917 QTime Klasse . . . . . . . . . . . 623 QTimer Klasse . . . . . . . . . 632 QTimerEvent Klasse . . . 840 QTimerEvent Klasse . . . 634 QToolButton Klasse . . . 267 QToolTipGroup Klasse 271 QTranslator Klasse . . . 948 QTsciiCodec Klasse . . . 954 QUriDrag Klasse . . . . . . . 615 QUrl Klasse . . . . . . . . . . . . 974 QUrlInfo Klasse . . . . . . . 976 QUrlOperator Klasse . 965 QValidator Klasse . . . . 790 QValueList Klasse . . . . 573 QValueListConstIterator Klasse . . . . . . . . . . . . . . 575 QValueListIterator Klasse . . . . . . . . . . . . . . 575 QValueStack Klasse . . . 584 QVBox Klasse . . . . . . . . . . . 374 QVBoxLayout Klasse . . . 378 QVector Klasse . . . . . . 540 QWaitCondition Klasse . . . 937 qWarning Funktion . . . . 955 QWhatsThis Klasse . . . . 271 QWheelEvent Klasse . . . 830 QWidget Klasse . . . . . . . . 125 QWidgetStack Klasse . 370 QWindowsStyle Klasse 203 QWizard Klasse . . . . . . . . 456 QWMatrix Klasse . . . . . . . 688 QXmlAttributes Klasse . . . 1038 QXmlContentHandler Klasse . . . . . . . . . . . . . 1032 QXmlDeclHandler Klasse . 1036 QXmlDefaultHandler Klasse . . . . . . . . . . . . . 1037 1161 Index QXmlDTDHandler Klasse . . . 1035 QXmlEntityResolver Klasse . . . . . . . . . . . . . 1035 QXmlErrorHandler Klasse 1034 QXmlInputSource Klasse . 1040 QXmlLexicalHandler Klasse . . . . . . . . . . . . . 1037 QXmlLocator Klasse . 1039 QXmlNameSpaceSupport Klasse . . . . . . . . . . . . . 1042 QXmlParseException Klasse . . . . . . . . . . . . . 1035 QXmlReader Klasse . . . 1040 QXmlSimpleReader Klasse 1041 R Rasterung (Graphik) . . . . Referenz . . . . . . . . . . . . . . . . Reguläre Ausdrücke . . . . Resize-Events . . . . . . . . . . . RGB-Farbmodell . . . . . . . . Richtext . . . . . . . . . . . . . . . . 720 117 799 843 146 236 S SAX2-Schnittstelle . . . . . 1027 Schiebebalken . . . . . . 128, 224 Schließ-Events . . . . . . . . . . 849 Screenshots . . . . . . . . . . . . . 752 Scrollviews . . . . . . . . . . . . . 312 Semaphore . . . . . . . . . . . . . 927 setGeometry() . . . . . . . 202 setMaximumHeight() 202 setMaximumSize() . . . 202 setMinimumHeight() 202 setMinimumSize() . . . 202 setMinimumWidth() . 202 setPalette() . . . . . . . . 201 setStyle() . . . . . . . . . . . 203 shallow copy-Sharing . . . 532 Show-Events . . . . . . . . . . . 849 Sichtbarkeits-Events . . . . 849 Signal-Slot-Konzept . . . . 128, 135, 869 sizeHint() . . . . . . . . . . . 202 Sound . . . . . . . . . . . . . . . . . . 786 1162 Spinboxen . . . . . . . . . . . . . . Splitter . . . . . . . . . . . . . . . . . Statuszeile . . . . . . . . . . . . . . Strings in Qt . . . . . . . . . . . . Subwidget-Events . . . . . . Synthetische Events . . . . . 227 363 279 137 852 858 T Tabdialog . . . . . . . . . . . . . . . 446 Tabelle Einfach . . . . . . . . . . . . . . . 333 Kalkulation . . . . . . . . . . . 341 Komfortabel . . . . . . . . . . 341 Kopf . . . . . . . . . . . . . . . . . . 344 Spreadsheet . . . . . . . . . . 341 Tabelle von Bildern . . . . . 898 Tastatur-Events . . . . . . . . . 834 Tastaturfokus . . . . . . . . . . . 813 Testausgaben . . . . . . . . . . . 955 Textanzeige HTML . . . . . . . . . . . . . . . . 236 Komfortabel . . . . . . . . . . 236 Richtext . . . . . . . . . . . . . . 236 Textbrowser . . . . . . . . . . . . 236 Texteingabe . . . . . . . . . . . . . 246 Threads . . . . . . . . . . . . . . . . . 917 Tiefe Kopie . . . . . . . . . . . . . 532 Timer . . . . . . . . . . . . . . . . . . . 632 Timer-Events . . . . . . . 634, 840 tmake Tool . . . . . . . . 115, 1149 tmake Tool . . . . . . . . . . . . . 120 Tool Ebuilder . . . . . . . . . . . . . 1142 findtr . . . . . . . . . . . . . . 948 linguist . . . . . . . . . . . . 947 lrelease . . . . . . . . . . . . 948 lupdate . . . . . . . . . . . . . 945 make . . . . . . . . . . . . 120, 1149 mergetr . . . . . . . . . . . . . 948 msg2qm . . . . . . . . . . . . . . 948 progen . . . . . . . . . . . . . 1154 qm2ts . . . . . . . . . . . . . . . . 948 Qt-Designer . . . . . . . . . 1117 QtArchitect . . . . . . . . . . 1142 QtEz . . . . . . . . . . . . . . . . 1142 tmake . . . . . . 115, 120, 1149 uic . . . . . . . . . . . . . . . . . 1124 Tooltips . . . . . . . . . . . . . . . . . 271 Transformationen (Graphik) 675 U uic Compiler . . . . . . . . . 1124 Unicode . . . . . . . . . . . . . . . . 943 Unified Modeling Language (UML) . . . . . . . . . . . . . . . 13 URI-Referenzen . . . . . . . . . 615 V Validierung von Eingaben . . 790 Versteck-Events . . . . . . . . . 848 View-Transformationen (Graphik) . . . . . . . . . . 692 Viewport-Transformationen (Graphik) . . . . . . . . . . 698 Vordefinierte Datentypen . . . 521 Vordefinierte Dialogfenster . 417 Vordefinierte Datenstrukturen . . . . 521 W warning() . . . . . . . . . . . . 171 Werkzeugleiste . . . . . . . . . 267 Widget Begriff . . . . . . . . . . . . . . . . 117 Widgetstack . . . . . . . . . . . . 370 Window-Transformationen (Graphik) . . . . . . . . . . 692 Wizards . . . . . . . . . . . . . . . . 456 World-Transformationen (Graphik) . . . . . . . . . . 675 X XML DOM . . . . . . . . . . . . . . . . 1053 SAX2 . . . . . . . . . . . . . . . . 1027 XML-Parser . . . . . . . . . . . 1027 Z Zeichenketten in Qt . . . . . Zeit . . . . . . . . . . . . . . . . . . . . . Zeit und Datum . . . . . . . . Zeitschaltuhren . . . . . . . . . Zuordnung von Widgets 137 623 628 632 352