Getting Started with Qt/de: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=Die ersten Schritte in Qt=
h1. Die ersten Schritte in Qt


Willkommen in der Welt von Qt – dem Werkzeug für plattformunabhängige <span class="caps">GUI</span>-Entwicklung ('''<span class="caps">GUI</span> = graphical user interface''', also eine graphische Benutzerschnittstelle). In dieser Einführung erklären wir die Grundlagen von Qt, am Beispiel eines einfachen Notepad-Programmes, welches wir Schritt für Schritt entwickeln werden. Nach der Lektüre dieses Artikels, werden Sie in der Lage sein, tiefer in die Übersichten und <span class="caps">API</span>-Dokumentationen einzutauchen und die Informationen zu finden, die Sie bei der Entwicklung Ihrer Anwendungen benötigen.
Willkommen in der Welt von Qt – dem Werkzeug für plattformunabhängige GUI-Entwicklung ('''GUI = graphical user interface''', also eine graphische Benutzerschnittstelle). In dieser Einführung erklären wir die Grundlagen von Qt, am Beispiel eines einfachen Notepad-Programmes, welches wir Schritt für Schritt entwickeln werden. Nach der Lektüre dieses Artikels, werden Sie in der Lage sein, tiefer in die Übersichten und API-Dokumentationen einzutauchen und die Informationen zu finden, die Sie bei der Entwicklung Ihrer Anwendungen benötigen.


==Hallo Notepad==
== Hallo Notepad ==


In unserem ersten Beispiel soll einfach ein Eingabefeld in einem Fenster angezeigt werden das wohl einfachste Qt Programm mit einer <span class="caps">GUI</span>.
In unserem ersten Beispiel soll einfach ein Eingabefeld in einem Fenster angezeigt werden - das wohl einfachste Qt Programm mit einer GUI.


[[Image:gs1.png|Ein Texteingabefenster]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs1.png|Ein Texteingabefenster]]


Und hier ist der zugehörige Quellcode:<br />
Und hier ist der zugehörige Quellcode:<br /><code>#include &lt;QApplication&amp;gt;<br />#include &lt;QTextEdit&amp;gt;


Gehen wir nun den Code Schritt für Schritt durch. In den ersten beiden Zeilen werden die Header-Dateien für [http://doc.trolltech.com/4.7/qapplication.html QApplication] ''[doc.trolltech.com]'' und [http://doc.trolltech.com/4.7/qtextedit.html QTextEdit] ''[doc.trolltech.com]'' eingebunden, welches die beiden Klassen sind, die wir für dieses Beispiel benötigen. Für jede Klasse in Qt existiert eine nach ihr benannte Header-Datei.
int main(int argv, char **args)<br />{<br /> QApplication app(argv, args);<br /> QTextEdit textEdit;<br /> textEdit.show();


In '''Zeile 6''' wird das QApplication-Objekt angelegt. Dieses Objekt verwaltet die Anwendungs-Ressourcen und wird für jedes Qt-Programm benötigt, welches eine <span class="caps">GUI</span> besitzt. Es werden außerdem die Variablen argv und args übergeben, da Qt auch einige Kommandozeilenparameter verarbeitet.
return app.exec&amp;amp;#40;&amp;#41;;<br />}</code>


In '''Zeile 7''' wird das QTextEdit-Objekt erstellt. Ein Texteingabefeld ist ein graphisches Element in der <span class="caps">GUI</span>. In Qt, werden solche Elemente '''Widgets''' genannt. Beispiele für andere Widgets sind Schieberegler (scroll bars), Beschriftungen (labels), oder eine Options-Auswahl (radio buttons). Ein Widget kann außerdem als Behälter für andere Widgets dienen; ein Dialog oder das Anwendungsfenster sind beispielsweise solche Behälter.
Gehen wir nun den Code Schritt für Schritt durch. In den ersten beiden Zeilen werden die Header-Dateien für &quot;QApplication&amp;quot;:http://doc.trolltech.com/4.7/qapplication.html und &quot;QTextEdit&amp;quot;:http://doc.trolltech.com/4.7/qtextedit.html eingebunden, welches die beiden Klassen sind, die wir für dieses Beispiel benötigen. Für jede Klasse in Qt existiert eine nach ihr benannte Header-Datei.
 
In '''Zeile 6''' wird das QApplication-Objekt angelegt. Dieses Objekt verwaltet die Anwendungs-Ressourcen und wird für jedes Qt-Programm benötigt, welches eine GUI besitzt. Es werden außerdem die Variablen argv und args übergeben, da Qt auch einige Kommandozeilenparameter verarbeitet.
 
In '''Zeile 7''' wird das QTextEdit-Objekt erstellt. Ein Texteingabefeld ist ein graphisches Element in der GUI. In Qt, werden solche Elemente '''Widgets''' genannt. Beispiele für andere Widgets sind Schieberegler (scroll bars), Beschriftungen (labels), oder eine Options-Auswahl (radio buttons). Ein Widget kann außerdem als Behälter für andere Widgets dienen; ein Dialog oder das Anwendungsfenster sind beispielsweise solche Behälter.


Danach wird unser Texteingabefeld in '''Zeile 9''' in seinem eigenen Fensterrahmen schließlich sichtbar gemacht. Da Widgets auch die Funktion von Containern erfüllen (zum Beispiel ein QMainWindow, welches Werkzeugleisten, Menüs, eine Statusbar und einige andere Widgets enthalten könnte), ist es möglich ein einzelnes Widget in seinem eigenen Fenster anzeigen zu lassen. Widgets sind standardmäßig nicht sichtbar, sie können aber mit der Funktion show() sichtbar gemacht werden.
Danach wird unser Texteingabefeld in '''Zeile 9''' in seinem eigenen Fensterrahmen schließlich sichtbar gemacht. Da Widgets auch die Funktion von Containern erfüllen (zum Beispiel ein QMainWindow, welches Werkzeugleisten, Menüs, eine Statusbar und einige andere Widgets enthalten könnte), ist es möglich ein einzelnes Widget in seinem eigenen Fenster anzeigen zu lassen. Widgets sind standardmäßig nicht sichtbar, sie können aber mit der Funktion show() sichtbar gemacht werden.


'''Zeile 10''' schließlich startet die Ereignisschleife von QApplication. Sobald eine Qt Anwendung läuft, werden Ereignisse erzeugt und an die Widgets der Anwendung geschickt. Solche Ereignisse werden beispielsweise beim Drücken von Maus- und Tastaturtasten generiert. Sobald man einen Text in das Eingabefeld eingibt, empfängt dieses die “Taste gedrückt”-Ereignisse und reagiert darauf in <br /> dem es den eingegebenen Text darstellt.
'''Zeile 10''' schließlich startet die Ereignisschleife von QApplication. Sobald eine Qt Anwendung läuft, werden Ereignisse erzeugt und an die Widgets der Anwendung geschickt. Solche Ereignisse werden beispielsweise beim Drücken von Maus- und Tastaturtasten generiert. Sobald man einen Text in das Eingabefeld eingibt, empfängt dieses die &quot;Taste gedrückt&amp;quot;-Ereignisse und reagiert darauf in<br />dem es den eingegebenen Text darstellt.


Um die Anwendung zu erstellen und auszuführen, öffne die Kommandozeile und wechsele in das Verzeichnis, in dem sich die .cpp Datei des Programms befindet. Tippe folgendes ein, um das Programm zu erstellen:
Um die Anwendung zu erstellen und auszuführen, öffne die Kommandozeile und wechsele in das Verzeichnis, in dem sich die .cpp Datei des Programms befindet. Tippe folgendes ein, um das Programm zu erstellen:


Nun existiert eine ausführbare Datei im part1-Verzeichnis (Unter Windows kann es sein, dass anstatt make der Befehl '''nmake''' verwendet werden muss. Außerdem wird die Anwendung im Verzeichnis part1/debug, oder part1/release erstellt). '''qmake''' ist Qt’s Werkzeug zum Erstellen und benutzt dazu eine Konfigurationsdatei. qmake generiert diese Datei für uns, wenn wir es mit dem Argurment “-project” aufrufen. Es verarbeitet die Konfigurationsdatei (mit der Dateiendung .pro) und erzeugt eine Makefile, welche für die Erstellung des Programmes benötigt wird. Wir werden das Schreiben eigener .pro-Dateien später noch behandeln.
<code>qmake -project<br />qmake<br />make</code>


===Weitere Informationen===
Nun existiert eine ausführbare Datei im part1-Verzeichnis (Unter Windows kann es sein, dass anstatt make der Befehl '''nmake''' verwendet werden muss. Außerdem wird die Anwendung im Verzeichnis part1/debug, oder part1/release erstellt). '''qmake''' ist Qt's Werkzeug zum Erstellen und benutzt dazu eine Konfigurationsdatei. qmake generiert diese Datei für uns, wenn wir es mit dem Argurment &quot;-project&amp;quot; aufrufen. Es verarbeitet die Konfigurationsdatei (mit der Dateiendung .pro) und erzeugt eine Makefile, welche für die Erstellung des Programmes benötigt wird. Wir werden das Schreiben eigener .pro-Dateien später noch behandeln.


* Widgets und Fenstergeometrie: [http://doc.qt.nokia.com/4.7/application-windows.html Fenster und Dialog-Widgets] ''[doc.qt.nokia.com]''
=== Weitere Informationen ===
* Ereignisse und Ereignisbehandlung: [http://doc.qt.nokia.com/4.7/eventsandfilters.html Das Ereignis-System] ''[doc.qt.nokia.com]''


==Hinzufügen eines Beenden-Knopfes==
* Widgets und Fenstergeometrie: &quot;Fenster und Dialog-Widgets&amp;quot;:http://doc.qt.nokia.com/4.7/application-windows.html
* Ereignisse und Ereignisbehandlung: &quot;Das Ereignis-System&amp;quot;:http://doc.qt.nokia.com/4.7/eventsandfilters.html


In einer realen Anwendung wird normalerweise mehr benötigt, als ein einzelnes Widget. Daher werden wir nun einen [http://doc.trolltech.com/4.7/qpushbutton.html QPushButton] ''[doc.trolltech.com]'' unter dem Eingabefeld anlegen, der die Anwendung schließt, sobald er gedrückt wird (z.B. wenn mit der Maus darauf geklickt wird).
== Hinzufügen eines Beenden-Knopfes ==


[[Image:gs2.png|Ein Knopf zum Beenden der Anwendung]]
In einer realen Anwendung wird normalerweise mehr benötigt, als ein einzelnes Widget. Daher werden wir nun einen &quot;QPushButton&amp;quot;:http://doc.trolltech.com/4.7/qpushbutton.html unter dem Eingabefeld anlegen, der die Anwendung schließt, sobald er gedrückt wird (z.B. wenn mit der Maus darauf geklickt wird).


Werfen wir zunächst einen Blick auf den Code:<br />
[[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|Ein Knopf zum Beenden der Anwendung]]


In '''Zeile 1''' wird der Header QtGui eingebunden, der alle <span class="caps">GUI</span> Klassen in Qt enthält.
Werfen wir zunächst einen Blick auf den Code:<br /><code>#include &lt;QtGui&amp;gt;


Interessant ist '''Zeile 10''' in der wir Qt’s Slot und Signal Mechanismus verwenden, um die Applikation zu beenden, sobald der Beenden-Button gedrückt wurde. Ein '''Slot''' ist eine Funktion, die zur Laufzeit über ihren Namen(eine Zeichenkette bestehend aus Buchstaben) aufgerufen werden kann. Ein '''Signal''' hingegen ist eine Funktion die, wenn sie aufgerufen wird, alle Slots, die mit dem Signal verbunden wurden, aufruft. Wir sagen dazu auch: Der Slot wird mit dem Signal verbunden ('''connect''') und das Signal wird emittiert ('''emit'''), also gesendet.
int main(int argv, char **args)<br />{<br /> QApplication app(argv, args);


'''quit()''' ist ein Slot von QApplication, der die Anwendung beendet. '''clicked()''' ist ein Signal, welches von QPushButton emittiert wird, nachdem der Knopf gedrückt wurde. Die statische Funktion '''QObject::connect()''' übernimmt das Verbinden von Slot und Signal. '''<span class="caps">SIGNAL</span>''' und '''<span class="caps">SLOT</span>''' sind zwei Makros, welche die Funktionssignaturen des Signals und des Slots, die verbunden werden sollen, übernehmen. Außerdem müssen wir die Zeiger zu den Objekten, welche das Signal senden und empfangen sollen, übergeben.
QTextEdit textEdit;<br /> QPushButton quitButton(&quot;Quit&amp;quot;);


In '''Zeile 12''' wird ein [http://doc.trolltech.com/4.7/qvboxlayout.html QVBoxLayout] ''[doc.trolltech.com]'' erstellt. Wie schon erwähnt wurde, können Widgets als Behälter für andere Widgets dienen. Es ist zwar möglich, die Größe und Position von Kind-Widgets direkt zu setzen, oft ist es aber einfacher dafür ein Layout zu verwenden. Ein Layout verwaltet die Abmessungen und Lage der Kinder in einem Widget. QVBoxLayout beispielsweise, ordnet seine Kind-Widgets vertikal in einer Spalte an.
QObject::connect(&amp;quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));


Das Texteingabe-Feld und der Knopf werden dem Layout in '''Zeile 13 und 14''' hinzugefügt. In '''Zeile 17''' wird schließlich das Layout einem Widget zugewiesen.
QVBoxLayout layout;<br /> layout.addWidget(&amp;textEdit);<br /> layout.addWidget(&amp;quitButton);


===Weitere Informationen===
QWidget window;<br /> window.setLayout(&amp;layout);


* Signale und Slots: [http://doc.qt.nokia.com/4.7/signalsandslots.html Signals &amp; Slots] ''[doc.qt.nokia.com]''
window.show();
* Layouts: [http://doc.qt.nokia.com/4.7/layout.html Layout Management] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com Widgets and Layouts] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-layouts.html/4.7/widgets-and-layouts.html Layout Beispiele] ''[doc.qt.nokia.com]''
* In Qt enthaltene Widgets: [http://doc.qt.nokia.com/4.7/gallery.html Qt Widget Gallerie] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-widgets.html Widget Beispiele] ''[doc.qt.nokia.com]''


==Von QWidget ableiten==
return app.exec&amp;amp;#40;&amp;#41;;<br />}</code>


Wenn der Nutzer die Anwendung schließt, möchte man vielleicht, dass ein Dialog geöffnet wird, in dem sie oder er gefragt wird, ob die Anwendung wirklich geschlossen werden soll. In diesem Beispiel werden wir eine eigene, von QWidget abgeleitete, Klasse erstellen, und einen Slot hinzufügen, den wir dann mit dem '''Beenden-Knopf''' verbinden.
In '''Zeile 1''' wird der Header QtGui eingebunden, der alle GUI Klassen in Qt enthält.


[[Image:gs3.png|Von QWidget ableiten]]
Interessant ist '''Zeile 10''' in der wir Qt's Slot und Signal Mechanismus verwenden, um die Applikation zu beenden, sobald der Beenden-Button gedrückt wurde. Ein '''Slot''' ist eine Funktion, die zur Laufzeit über ihren Namen(eine Zeichenkette bestehend aus Buchstaben) aufgerufen werden kann. Ein '''Signal''' hingegen ist eine Funktion die, wenn sie aufgerufen wird, alle Slots, die mit dem Signal verbunden wurden, aufruft. Wir sagen dazu auch: Der Slot wird mit dem Signal verbunden ('''connect''') und das Signal wird emittiert ('''emit'''), also gesendet.


Schauen wir uns den Code an<br />
'''quit()''' ist ein Slot von QApplication, der die Anwendung beendet. '''clicked()''' ist ein Signal, welches von QPushButton emittiert wird, nachdem der Knopf gedrückt wurde. Die statische Funktion '''QObject::connect()''' übernimmt das Verbinden von Slot und Signal. '''SIGNAL ()* und *SLOT()''' sind zwei Makros, welche die Funktionssignaturen des Signals und des Slots, die verbunden werden sollen, übernehmen. Außerdem müssen wir die Zeiger zu den Objekten, welche das Signal senden und empfangen sollen, übergeben.


Das '''Q_OBJECT''' Makro muss als erstes in unsere Klassendefinition, und deklariert die Klasse als QObject (Natürlich muss sie auch von QObject abgeleitet sein). QObject fügt einer normalen C++-Klasse verschiedene Fähigkeiten hinzu. Beispielsweise können zur Laufzeit der Klassenname und Slotnamen ermittelt werden. Es ist auch möglich die Parametertypen eines Slots abzufragen und ihn auszuführen.
In '''Zeile 12''' wird ein &quot;QVBoxLayout&amp;quot;:http://doc.trolltech.com/4.7/qvboxlayout.html erstellt. Wie schon erwähnt wurde, können Widgets als Behälter für andere Widgets dienen. Es ist zwar möglich, die Größe und Position von Kind-Widgets direkt zu setzen, oft ist es aber einfacher dafür ein Layout zu verwenden. Ein Layout verwaltet die Abmessungen und Lage der Kinder in einem Widget. QVBoxLayout beispielsweise, ordnet seine Kind-Widgets vertikal in einer Spalte an.


In '''Zeile 9''' wird der Slot quit() deklariert, was mit dem '''slots-Makro''' recht einfach ist. Der quit()-Slot kann nun zu Signalen mit passender Signatur verbunden werden (in diesem Fall zu Signalen, die keine Parameter haben).
Das Texteingabe-Feld und der Knopf werden dem Layout in '''Zeile 13 und 14''' hinzugefügt. In '''Zeile 17''' wird schließlich das Layout einem Widget zugewiesen.


Anstatt in der main()-Funktion die <span class="caps">GUI</span> zu erstellen und den Slot zu verbinden, nutzen wir nun den Konstruktor der Notepad-Klasse.
=== Weitere Informationen ===


Wie man in der Klassen-Definition gesehen hat, haben wir Zeiger auf unsere QObjects (textEdit und quitButton) verwendet. Eine Faustregel ist, QObjects immer auf dem Heap anzulegen und sie niemals zu kopieren.
* Signale und Slots: &quot;Signals &amp; Slots&amp;quot;:http://doc.qt.nokia.com/4.7/signalsandslots.html
* Layouts: &quot;Layout Management&amp;quot;:http://doc.qt.nokia.com/4.7/layout.html, &quot;Widgets and Layouts&amp;quot;:http://doc.qt.nokia.com, &quot;Layout Beispiele&amp;quot;:http://doc.qt.nokia.com/4.7/examples-layouts.html/4.7/widgets-and-layouts.html
* In Qt enthaltene Widgets: &quot;Qt Widget Gallerie&amp;quot;:http://doc.qt.nokia.com/4.7/gallery.html, &quot;Widget Beispiele&amp;quot;:http://doc.qt.nokia.com/4.7/examples-widgets.html


Dann haben wir die tr()-Funktion auf unsere Texte angewendet. Diese Funktion ist notwendig, wenn Sie Ihre Applikation in mehreren Sprachen (z.B. in Englisch oder Chinesisch) anbieten möchten. Wir werden hier nicht weiter auf Details eingehen, aber Sie können dem Qt Linguist Link weiter unten folgen, um mehr Informationen zu erhalten.
== Von QWidget ableiten ==


===Weitere Informationen===
Wenn der Nutzer die Anwendung schließt, möchte man vielleicht, dass ein Dialog geöffnet wird, in dem sie oder er gefragt wird, ob die Anwendung wirklich geschlossen werden soll. In diesem Beispiel werden wir eine eigene, von QWidget abgeleitete, Klasse erstellen, und einen Slot hinzufügen, den wir dann mit dem '''Beenden-Knopf''' verbinden.


* tr() and internationalization: [http://doc.qt.nokia.com/4.7/linguist-manual.html Qt Linguist Handbuch] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/i18n-source-translation.html Übersetzbaren Code schreiben] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/linguist-hellotr.html Hallo tr()-Beispiel] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/internationalization.html Internationalisierung mit Qt] ''[doc.qt.nokia.com]''
[[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|Von QWidget ableiten]]
* [http://doc.qt.nokia.com/4.7/qtwebkit-bridge.html#qobjects QObjects] ''[doc.qt.nokia.com]'' und das Qt Objekt Modell (dies ist sehr wichtig, um Qt zu verstehen): [http://doc.qt.nokia.com/4.7/object.html Objekt Modell] ''[doc.qt.nokia.com]''
* qmake und das Qt Build System: [http://doc.qt.nokia.com/4.7/qmake-manual.html qmake Handbuch] ''[doc.qt.nokia.com]''


==Eine .pro Datei erstellen==
Schauen wir uns den Code an<br /><code>class Notepad : public QWidget<br />{<br /> Q_OBJECT


In diesem Beispiel schreiben wir unsere eigene .pro Datei, anstatt von qmake’s -project Option Gebrauch zu machen.
public:<br /> Notepad();


Die folgenden Befehle erstellen das Beispiel-Projekt:
private slots:<br /> void quit();


==Verwendung von QMainWindow==
private:<br /> QTextEdit *textEdit;<br /> QPushButton *quitButton;<br /> };</code>


Für viele Anwendungen ist es von Vorteil, [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] ''[doc.qt.nokia.com]'' zu benutzen, da es sein eigenes Layout mitbringt, zu dem man eine Menüleiste, Andockende Widgets, Werkzeugleisten und eine Statusleiste hinzufügen kann. [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] ''[doc.qt.nokia.com]'' besitzt einen zentralen Bereich, der von jedem beliebigen Widget genutzt werden kann. In unserem Fall werden wir dort das Texteingabefeld platzieren.
Das '''Q_OBJECT''' Makro muss als erstes in unsere Klassendefinition, und deklariert die Klasse als QObject (Natürlich muss sie auch von QObject abgeleitet sein). QObject fügt einer normalen C++-Klasse verschiedene Fähigkeiten hinzu. Beispielsweise können zur Laufzeit der Klassenname und Slotnamen ermittelt werden. Es ist auch möglich die Parametertypen eines Slots abzufragen und ihn auszuführen.


[[Image:gs4.png|Texteingabefeld in einem QMainWindow]]
In '''Zeile 9''' wird der Slot quit() deklariert, was mit dem '''slots-Makro''' recht einfach ist. Der quit()-Slot kann nun zu Signalen mit passender Signatur verbunden werden (in diesem Fall zu Signalen, die keine Parameter haben).


Betrachten wir die neue Notepad-Klassendefinition:
Anstatt in der main()-Funktion die GUI zu erstellen und den Slot zu verbinden, nutzen wir nun den Konstruktor der Notepad-Klasse.


Um ein Dokument speichern und öffnen zu können, fügen wir zwei neue Slots hinzu, die wir im nächsten Abschnitt implementieren.
<code>Notepad::Notepad()<br />{<br /> textEdit = new QTextEdit;<br /> quitButton = new QPushButton(tr(&quot;Quit&amp;quot;));


Es kommt häufig vor, dass im Hauptfenster der selbe Slot von mehreren Widgets aufgerufen werden soll. Zum Beispiel von Menüeinträgen und Knöpfen auf einer Werkzeugleiste. Um das zu vereinfachen, bietet Qt die Klasse [http://doc.qt.nokia.com/4.7/qaction.html QAction] ''[doc.qt.nokia.com]'' an, welche an mehrere Widgets übergeben, und an einen Slot gebunden werden können. Zum Beispiel können sowohl [http://doc.qt.nokia.com/4.7/qmenu.html QMenu] ''[doc.qt.nokia.com]'', als auch [http://doc.trolltech.com/4.7/qtoolbar.html QToolBar] ''[doc.trolltech.com]'' Menüeinträge und Werkzeug-Knöpfe für die gleichen QActions anlegen. Wie das funktioniert sehen wir gleich.
connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));


Genau wie vorhin, nutzen wir den Konstruktor unserer Notepad-Klasse, um die <span class="caps">GUI</span> zu erstellen.
QVBoxLayout '''layout = new QVBoxLayout;<br /> layout-&gt;addWidget(textEdit);<br /> layout-&gt;addWidget(quitButton);
<br /> setLayout(layout);
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}</code>
<br />p. Wie man in der Klassen-Definition gesehen hat, haben wir Zeiger auf unsere QObjects (textEdit und quitButton) verwendet. Eine Faustregel ist, QObjects immer auf dem Heap anzulegen und sie niemals zu kopieren.
<br />p. Dann haben wir die tr()-Funktion auf unsere Texte angewendet. Diese Funktion ist notwendig, wenn Sie Ihre Applikation in mehreren Sprachen (z.B. in Englisch oder Chinesisch) anbieten möchten. Wir werden hier nicht weiter auf Details eingehen, aber Sie können dem Qt Linguist Link weiter unten folgen, um mehr Informationen zu erhalten.
<br />h3. Weitere Informationen<br />''' tr() and internationalization: &quot;Qt Linguist Handbuch&amp;quot;:http://doc.qt.nokia.com/4.7/linguist-manual.html, &quot;Übersetzbaren Code schreiben&amp;quot;:http://doc.qt.nokia.com/4.7/i18n-source-translation.html, &quot;Hallo tr()-Beispiel&amp;quot;:http://doc.qt.nokia.com/4.7/linguist-hellotr.html, &quot;Internationalisierung mit Qt&amp;quot;:http://doc.qt.nokia.com/4.7/internationalization.html<br />* &quot;QObjects&amp;quot;:http://doc.qt.nokia.com/4.7/qtwebkit-bridge.html#qobjects und das Qt Objekt Modell (dies ist sehr wichtig, um Qt zu verstehen): &quot;Objekt Modell&amp;quot;:http://doc.qt.nokia.com/4.7/object.html<br />* qmake und das Qt Build System: &quot;qmake Handbuch&amp;quot;:http://doc.qt.nokia.com/4.7/qmake-manual.html


[http://doc.qt.nokia.com/4.7/qaction.html QAction] ''[doc.qt.nokia.com]'' werden mit dem Text erstellt, der auch in den Widgets erscheinen soll, zu denen wir sie hinzufügen (in userem Fall Menüeinträge). Wollten wir sie auch zu einer Werkzeugleiste hinzufügen, könnten wir für die Aktionen auch Icons festlegen.
== Eine .pro Datei erstellen ==


Wenn nun einer der Menüeinträge ausgewählt wird, löst der Eintrag die Aktion aus und der daran gebundene Slot wird aufgerufen.
In diesem Beispiel schreiben wir unsere eigene .pro Datei, anstatt von qmake's <s>project Option Gebrauch zu machen.
<br /><code> HEADERS = notepad.h<br />SOURCES = notepad.cpp  main.cpp</code>
<br />p. Die folgenden Befehle erstellen das Beispiel-Projekt:
<br /><code>qmake<br />make</code>
<br />h2. Verwendung von QMainWindow
<br />p. Für viele Anwendungen ist es von Vorteil, &quot;QMainWindow&amp;quot;:http://doc.qt.nokia.com/4.7/qmainwindow.html zu benutzen, da es sein eigenes Layout mitbringt, zu dem man eine Menüleiste, Andockende Widgets, Werkzeugleisten und eine Statusleiste hinzufügen kann. &quot;QMainWindow&amp;quot;:http://doc.qt.nokia.com/4.7/qmainwindow.html besitzt einen zentralen Bereich, der von jedem beliebigen Widget genutzt werden kann. In unserem Fall werden wir dort das Texteingabefeld platzieren.
<br />[[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|Texteingabefeld in einem QMainWindow]]
<br />p. Betrachten wir die neue Notepad-Klassendefinition:
<br /><code> #include &lt;QtGui&amp;gt;
<br />class Notepad : public QMainWindow<br />{<br /> Q_OBJECT
<br /> public:<br /> Notepad();
<br /> private slots:<br /> void open();<br /> void save();<br /> void quit();
<br /> private:<br /> QTextEdit *textEdit;
<br /> QAction *openAction;<br /> QAction *saveAction;<br /> QAction *exitAction;
<br /> QMenu '''fileMenu;<br />};</code>
<br />p. Um ein Dokument speichern und öffnen zu können, fügen wir zwei neue Slots hinzu, die wir im nächsten Abschnitt implementieren.
<br />p. Es kommt häufig vor, dass im Hauptfenster der selbe Slot von mehreren Widgets aufgerufen werden soll. Zum Beispiel von Menüeinträgen und Knöpfen auf einer Werkzeugleiste. Um das zu vereinfachen, bietet Qt die Klasse &quot;QAction&amp;quot;:http://doc.qt.nokia.com/4.7/qaction.html an, welche an mehrere Widgets übergeben, und an einen Slot gebunden werden können. Zum Beispiel können sowohl &quot;QMenu&amp;quot;:http://doc.qt.nokia.com/4.7/qmenu.html, als auch &quot;QToolBar&amp;quot;:http://doc.trolltech.com/4.7/qtoolbar.html Menüeinträge und Werkzeug-Knöpfe für die gleichen QActions anlegen. Wie das funktioniert sehen wir gleich.
<br />p. Genau wie vorhin, nutzen wir den Konstruktor unserer Notepad-Klasse, um die GUI zu erstellen.
<br /><code>Notepad::Notepad()<br />{<br /> saveAction = new QAction(tr(&quot;&amp;Open&amp;quot;), this);<br /> saveAction = new QAction(tr(&quot;&amp;Save&amp;quot;), this);<br /> exitAction = new QAction(tr(&quot;E&amp;amp;xit&amp;quot;), this);
<br /> connect(openAction, SIGNAL (triggered()), this, SLOT (open()));<br /> connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));<br /> connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
<br /> fileMenu = menuBar()<s>&gt;addMenu(tr(&quot;&amp;File&amp;quot;));<br /> fileMenu</s>&gt;addAction(openAction);<br /> fileMenu-&gt;addAction(saveAction);<br /> fileMenu-&gt;addSeparator();<br /> fileMenu-&gt;addAction(exitAction);
<br /> textEdit = new QTextEdit;<br /> setCentralWidget(textEdit);
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}</code>
<br />p. &quot;QAction&amp;quot;:http://doc.qt.nokia.com/4.7/qaction.html werden mit dem Text erstellt, der auch in den Widgets erscheinen soll, zu denen wir sie hinzufügen (in userem Fall Menüeinträge). Wollten wir sie auch zu einer Werkzeugleiste hinzufügen, könnten wir für die Aktionen auch Icons festlegen.
<br />p. Wenn nun einer der Menüeinträge ausgewählt wird, löst der Eintrag die Aktion aus und der daran gebundene Slot wird aufgerufen.
<br />h3. Weitere Informationen
<br />''' Hauptfenster und Hauptfenster-Klassen: &quot;Hauptfenster von Anwendungen&amp;quot;:http://doc.qt.nokia.com/4.7/mainwindow.html, &quot;Hauptfenster Beispiele&amp;quot;:http://doc.qt.nokia.com/4.7/examples-mainwindow.html<br />* MDI Anwendungen: &quot;MDI Bereich&amp;quot;:http://doc.qt.nokia.com/4.7/qmdiarea.html, &quot;MDI Beispiele&amp;quot;:http://doc.qt.nokia.com/4.7/mainwindows-mdi.html
<br />h2. Speichern und Laden
<br />p. Dieses Beispiel zeigt die Implementierung der Laden</s> und Speichern-Slots, die wir im vorigen Beispiel hinzugefügt haben.


===Weitere Informationen===
[[Image:http://doc.qt.nokia.com/4.7/images/gs5.png|Der Öffen-Dialog]]


* Hauptfenster und Hauptfenster-Klassen: [http://doc.qt.nokia.com/4.7/mainwindow.html Hauptfenster von Anwendungen] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-mainwindow.html Hauptfenster Beispiele] ''[doc.qt.nokia.com]''
Beginnen wir mit dem Öffnen-Slot
* <span class="caps">MDI</span> Anwendungen: [http://doc.qt.nokia.com/4.7/qmdiarea.html <span class="caps">MDI</span> Bereich] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/mainwindows-mdi.html <span class="caps">MDI</span> Beispiele] ''[doc.qt.nokia.com]''
 
==Speichern und Laden==
 
Dieses Beispiel zeigt die Implementierung der Laden- und Speichern-Slots, die wir im vorigen Beispiel hinzugefügt haben.


[[Image:gs5.png|Der Öffen-Dialog]]
<code>QString fileName = QFileDialog::getOpenFileName(this, tr(&quot;Open File&amp;quot;), &quot;&quot;, tr(&quot;Text Files ('''.txt);;C++ Files ('''.cpp *.h)&quot;));


Beginnen wir mit dem Öffnen-Slot
if (fileName != &quot;&quot;) {<br /> QFile file&amp;amp;#40;fileName&amp;amp;#41;;<br /> if (!file.open(QIODevice::ReadOnly)) {<br /> QMessageBox::critical(this, tr(&quot;Error&amp;quot;), tr(&quot;Could not open file&amp;quot;));<br /> return;<br /> }<br /> QString contents = file.readAll().constData();<br /> textEdit-&gt;setPlainText(contents);<br /> file.close();<br />}</code>


Im ersten Schritt wird der Anwender nach dem Namen der zu öffnenden Datei gefragt. Qt bietet dazu den [http://doc.trolltech.com/4.7/qfiledialog.html QFileDialog] ''[doc.trolltech.com]'', in dem der Nutzer eine Datei auswählen kann. Das Bild zeigt den Dialog unter Kubuntu. Die statische Funktion '''getOpenFileName()''' zeigt einen modalen Datei-Auswahl-Dialog der erst zur Hauptanwendung zurückkehrt, wenn der Anwender eine Datei ausgewählt, oder den Dialog geschlossen hat. Der Rückgabewert ist entweder der Pfad zur gewählten Datei, oder eine leere Zeichenkette, wenn der Nutzer den Dialog abgebrochen hat.
Im ersten Schritt wird der Anwender nach dem Namen der zu öffnenden Datei gefragt. Qt bietet dazu den &quot;QFileDialog&amp;quot;:http://doc.trolltech.com/4.7/qfiledialog.html, in dem der Nutzer eine Datei auswählen kann. Das Bild zeigt den Dialog unter Kubuntu. Die statische Funktion '''getOpenFileName()''' zeigt einen modalen Datei-Auswahl-Dialog der erst zur Hauptanwendung zurückkehrt, wenn der Anwender eine Datei ausgewählt, oder den Dialog geschlossen hat. Der Rückgabewert ist entweder der Pfad zur gewählten Datei, oder eine leere Zeichenkette, wenn der Nutzer den Dialog abgebrochen hat.


Nachdem wir überprüft haben, ob ein Dateipfad zurückgegeben wurde, versuchen wir die Datei mit der '''open()'''-Methode zu öffnen. Diese gibt den Wert true zurück, wenn die Datei erfolgreich geöffnet werden konnte. Wir werden an dieser Stelle nicht über Fehlerbehandlung sprechen, aber sie können den Links unter dem Eintrag “Weiterführende Informationen” folgen. Konnte die Datei nicht geöffnet werden, verwenden wir [http://doc.trolltech.com/4.7/qmessagebox.html QMessageBox] ''[doc.trolltech.com]'', um den Fehler in einem Dialog an zu zeigen (weitere Details können Sie in der Klassenbeschreibung von [http://doc.trolltech.com/4.7/qmessagebox.html QMessageBox] ''[doc.trolltech.com]'' nachlesen).
Nachdem wir überprüft haben, ob ein Dateipfad zurückgegeben wurde, versuchen wir die Datei mit der '''open()'''-Methode zu öffnen. Diese gibt den Wert true zurück, wenn die Datei erfolgreich geöffnet werden konnte. Wir werden an dieser Stelle nicht über Fehlerbehandlung sprechen, aber sie können den Links unter dem Eintrag &quot;Weiterführende Informationen&amp;quot; folgen. Konnte die Datei nicht geöffnet werden, verwenden wir &quot;QMessageBox&amp;quot;:http://doc.trolltech.com/4.7/qmessagebox.html, um den Fehler in einem Dialog an zu zeigen (weitere Details können Sie in der Klassenbeschreibung von &quot;QMessageBox&amp;quot;:http://doc.trolltech.com/4.7/qmessagebox.html nachlesen).


Das Lesen der Datei trivial. Wenn man die Funktion '''readAll()''' verwendet, wird der gesamte Inhalt der Datei in einem [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] ''[doc.qt.nokia.com]'' zurück liefert. Die Funktion '''constData()''' liefert alle Daten des Arrays als einen const char* Pointer zurück, wofür es in der QString Klasse einen Konstruktor gibt. Der Text kann dann im Textfeld angezeigt werden. Damit der Datei-Deskriptor wieder an das System zurück gegeben werden kann, schließen wir am Ende die Datei mit der '''close()'''-Methode
Das Lesen der Datei trivial. Wenn man die Funktion '''readAll()''' verwendet, wird der gesamte Inhalt der Datei in einem &quot;QByteArray&amp;quot;:http://doc.qt.nokia.com/4.7/qbytearray.html zurück liefert. Die Funktion '''constData()''' liefert alle Daten des Arrays als einen const char* Pointer zurück, wofür es in der QString Klasse einen Konstruktor gibt. Der Text kann dann im Textfeld angezeigt werden. Damit der Datei-Deskriptor wieder an das System zurück gegeben werden kann, schließen wir am Ende die Datei mit der '''close()'''-Methode


Lassen Sie uns jetzt mit dem Save() Slot weiter machen
Lassen Sie uns jetzt mit dem Save() Slot weiter machen


Um den Inhalt des Textfeldes in eine Datei zu schreiben, benutzen wir die [http://doc.trolltech.com/4.7/qtextstream.html QTextStream] ''[doc.trolltech.com]'' Klasse, welche das QFile-Objekt umhüllt. Der Text-Stream kann QStrings direkt in die Datei schreiben; [http://doc.trolltech.com/4.7/qfile.html QFile] ''[doc.trolltech.com]'' aktzeptiert in der write()-Funktion von [http://doc.trolltech.com/4.7/qiodevice.html <span class="caps">QIOD</span>evice] ''[doc.trolltech.com]'' hingegen nur Rohdaten (char*).
<code>QString fileName = QFileDialog::getSaveFileName(this, tr(&quot;Save File&amp;quot;), &quot;&quot;, tr(&quot;Text Files ('''.txt);;C++ Files ('''.cpp '''.h)&quot;));
 
<br />if (fileName != &quot;&quot;) {<br /> QFile file&amp;amp;#40;fileName&amp;amp;#41;;<br /> if (!file.open(QIODevice::WriteOnly)) {<br /> // error message<br /> } else {<br /> QTextStream stream(&amp;file);<br /> stream &lt;&lt; textEdit-&gt;toPlainText();<br /> stream.flush();<br /> file.close();<br /> }<br />}</code>
===Weitere Informationen===
<br />p. Um den Inhalt des Textfeldes in eine Datei zu schreiben, benutzen wir die &quot;QTextStream&amp;quot;:http://doc.trolltech.com/4.7/qtextstream.html Klasse, welche das QFile-Objekt umhüllt. Der Text-Stream kann QStrings direkt in die Datei schreiben; &quot;QFile&amp;quot;:http://doc.trolltech.com/4.7/qfile.html aktzeptiert in der write()-Funktion von &quot;QIODevice&amp;quot;:http://doc.trolltech.com/4.7/qiodevice.html hingegen nur Rohdaten (char''').
 
* Dateien und EA-Geräte: [http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qiodevice.html <span class="caps">QIOD</span>evice] ''[doc.qt.nokia.com]''
 
===Categories:===


* [[:Category:German|German]]
=== Weitere Informationen<br />* Dateien und EA-Geräte: &quot;QFile&amp;quot;:http://doc.qt.nokia.com/4.7/qfile.html, &quot;QIODevice&amp;quot;:http://doc.qt.nokia.com/4.7/qiodevice.html ===

Revision as of 09:36, 24 February 2015

h1. Die ersten Schritte in Qt

Willkommen in der Welt von Qt – dem Werkzeug für plattformunabhängige GUI-Entwicklung (GUI = graphical user interface, also eine graphische Benutzerschnittstelle). In dieser Einführung erklären wir die Grundlagen von Qt, am Beispiel eines einfachen Notepad-Programmes, welches wir Schritt für Schritt entwickeln werden. Nach der Lektüre dieses Artikels, werden Sie in der Lage sein, tiefer in die Übersichten und API-Dokumentationen einzutauchen und die Informationen zu finden, die Sie bei der Entwicklung Ihrer Anwendungen benötigen.

Hallo Notepad

In unserem ersten Beispiel soll einfach ein Eingabefeld in einem Fenster angezeigt werden - das wohl einfachste Qt Programm mit einer GUI.

Ein Texteingabefenster

Und hier ist der zugehörige Quellcode:

#include &lt;QApplication&amp;gt;<br />#include &lt;QTextEdit&amp;gt;

int main(int argv, char **args)<br />{<br /> QApplication app(argv, args);<br /> QTextEdit textEdit;<br /> textEdit.show();

return app.exec&amp;amp;#40;&amp;#41;;<br />}

Gehen wir nun den Code Schritt für Schritt durch. In den ersten beiden Zeilen werden die Header-Dateien für "QApplication&quot;:http://doc.trolltech.com/4.7/qapplication.html und "QTextEdit&quot;:http://doc.trolltech.com/4.7/qtextedit.html eingebunden, welches die beiden Klassen sind, die wir für dieses Beispiel benötigen. Für jede Klasse in Qt existiert eine nach ihr benannte Header-Datei.

In Zeile 6 wird das QApplication-Objekt angelegt. Dieses Objekt verwaltet die Anwendungs-Ressourcen und wird für jedes Qt-Programm benötigt, welches eine GUI besitzt. Es werden außerdem die Variablen argv und args übergeben, da Qt auch einige Kommandozeilenparameter verarbeitet.

In Zeile 7 wird das QTextEdit-Objekt erstellt. Ein Texteingabefeld ist ein graphisches Element in der GUI. In Qt, werden solche Elemente Widgets genannt. Beispiele für andere Widgets sind Schieberegler (scroll bars), Beschriftungen (labels), oder eine Options-Auswahl (radio buttons). Ein Widget kann außerdem als Behälter für andere Widgets dienen; ein Dialog oder das Anwendungsfenster sind beispielsweise solche Behälter.

Danach wird unser Texteingabefeld in Zeile 9 in seinem eigenen Fensterrahmen schließlich sichtbar gemacht. Da Widgets auch die Funktion von Containern erfüllen (zum Beispiel ein QMainWindow, welches Werkzeugleisten, Menüs, eine Statusbar und einige andere Widgets enthalten könnte), ist es möglich ein einzelnes Widget in seinem eigenen Fenster anzeigen zu lassen. Widgets sind standardmäßig nicht sichtbar, sie können aber mit der Funktion show() sichtbar gemacht werden.

Zeile 10 schließlich startet die Ereignisschleife von QApplication. Sobald eine Qt Anwendung läuft, werden Ereignisse erzeugt und an die Widgets der Anwendung geschickt. Solche Ereignisse werden beispielsweise beim Drücken von Maus- und Tastaturtasten generiert. Sobald man einen Text in das Eingabefeld eingibt, empfängt dieses die "Taste gedrückt&quot;-Ereignisse und reagiert darauf in
dem es den eingegebenen Text darstellt.

Um die Anwendung zu erstellen und auszuführen, öffne die Kommandozeile und wechsele in das Verzeichnis, in dem sich die .cpp Datei des Programms befindet. Tippe folgendes ein, um das Programm zu erstellen:

qmake -project<br />qmake<br />make

Nun existiert eine ausführbare Datei im part1-Verzeichnis (Unter Windows kann es sein, dass anstatt make der Befehl nmake verwendet werden muss. Außerdem wird die Anwendung im Verzeichnis part1/debug, oder part1/release erstellt). qmake ist Qt's Werkzeug zum Erstellen und benutzt dazu eine Konfigurationsdatei. qmake generiert diese Datei für uns, wenn wir es mit dem Argurment "-project&quot; aufrufen. Es verarbeitet die Konfigurationsdatei (mit der Dateiendung .pro) und erzeugt eine Makefile, welche für die Erstellung des Programmes benötigt wird. Wir werden das Schreiben eigener .pro-Dateien später noch behandeln.

Weitere Informationen

Hinzufügen eines Beenden-Knopfes

In einer realen Anwendung wird normalerweise mehr benötigt, als ein einzelnes Widget. Daher werden wir nun einen "QPushButton&quot;:http://doc.trolltech.com/4.7/qpushbutton.html unter dem Eingabefeld anlegen, der die Anwendung schließt, sobald er gedrückt wird (z.B. wenn mit der Maus darauf geklickt wird).

Ein Knopf zum Beenden der Anwendung

Werfen wir zunächst einen Blick auf den Code:

#include &lt;QtGui&amp;gt;

int main(int argv, char **args)<br />{<br /> QApplication app(argv, args);

QTextEdit textEdit;<br /> QPushButton quitButton(&quot;Quit&amp;quot;);

QObject::connect(&amp;quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));

QVBoxLayout layout;<br /> layout.addWidget(&amp;textEdit);<br /> layout.addWidget(&amp;quitButton);

QWidget window;<br /> window.setLayout(&amp;layout);

window.show();

return app.exec&amp;amp;#40;&amp;#41;;<br />}

In Zeile 1 wird der Header QtGui eingebunden, der alle GUI Klassen in Qt enthält.

Interessant ist Zeile 10 in der wir Qt's Slot und Signal Mechanismus verwenden, um die Applikation zu beenden, sobald der Beenden-Button gedrückt wurde. Ein Slot ist eine Funktion, die zur Laufzeit über ihren Namen(eine Zeichenkette bestehend aus Buchstaben) aufgerufen werden kann. Ein Signal hingegen ist eine Funktion die, wenn sie aufgerufen wird, alle Slots, die mit dem Signal verbunden wurden, aufruft. Wir sagen dazu auch: Der Slot wird mit dem Signal verbunden (connect) und das Signal wird emittiert (emit), also gesendet.

quit() ist ein Slot von QApplication, der die Anwendung beendet. clicked() ist ein Signal, welches von QPushButton emittiert wird, nachdem der Knopf gedrückt wurde. Die statische Funktion QObject::connect() übernimmt das Verbinden von Slot und Signal. SIGNAL ()* und *SLOT() sind zwei Makros, welche die Funktionssignaturen des Signals und des Slots, die verbunden werden sollen, übernehmen. Außerdem müssen wir die Zeiger zu den Objekten, welche das Signal senden und empfangen sollen, übergeben.

In Zeile 12 wird ein "QVBoxLayout&quot;:http://doc.trolltech.com/4.7/qvboxlayout.html erstellt. Wie schon erwähnt wurde, können Widgets als Behälter für andere Widgets dienen. Es ist zwar möglich, die Größe und Position von Kind-Widgets direkt zu setzen, oft ist es aber einfacher dafür ein Layout zu verwenden. Ein Layout verwaltet die Abmessungen und Lage der Kinder in einem Widget. QVBoxLayout beispielsweise, ordnet seine Kind-Widgets vertikal in einer Spalte an.

Das Texteingabe-Feld und der Knopf werden dem Layout in Zeile 13 und 14 hinzugefügt. In Zeile 17 wird schließlich das Layout einem Widget zugewiesen.

Weitere Informationen

Von QWidget ableiten

Wenn der Nutzer die Anwendung schließt, möchte man vielleicht, dass ein Dialog geöffnet wird, in dem sie oder er gefragt wird, ob die Anwendung wirklich geschlossen werden soll. In diesem Beispiel werden wir eine eigene, von QWidget abgeleitete, Klasse erstellen, und einen Slot hinzufügen, den wir dann mit dem Beenden-Knopf verbinden.

Von QWidget ableiten

Schauen wir uns den Code an

class Notepad : public QWidget<br />{<br /> Q_OBJECT

public:<br /> Notepad();

private slots:<br /> void quit();

private:<br /> QTextEdit *textEdit;<br /> QPushButton *quitButton;<br /> };

Das Q_OBJECT Makro muss als erstes in unsere Klassendefinition, und deklariert die Klasse als QObject (Natürlich muss sie auch von QObject abgeleitet sein). QObject fügt einer normalen C++-Klasse verschiedene Fähigkeiten hinzu. Beispielsweise können zur Laufzeit der Klassenname und Slotnamen ermittelt werden. Es ist auch möglich die Parametertypen eines Slots abzufragen und ihn auszuführen.

In Zeile 9 wird der Slot quit() deklariert, was mit dem slots-Makro recht einfach ist. Der quit()-Slot kann nun zu Signalen mit passender Signatur verbunden werden (in diesem Fall zu Signalen, die keine Parameter haben).

Anstatt in der main()-Funktion die GUI zu erstellen und den Slot zu verbinden, nutzen wir nun den Konstruktor der Notepad-Klasse.

Notepad::Notepad()<br />{<br /> textEdit = new QTextEdit;<br /> quitButton = new QPushButton(tr(&quot;Quit&amp;quot;));

connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));

QVBoxLayout '''layout = new QVBoxLayout;<br /> layout-&gt;addWidget(textEdit);<br /> layout-&gt;addWidget(quitButton);
<br /> setLayout(layout);
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}


p. Wie man in der Klassen-Definition gesehen hat, haben wir Zeiger auf unsere QObjects (textEdit und quitButton) verwendet. Eine Faustregel ist, QObjects immer auf dem Heap anzulegen und sie niemals zu kopieren.
p. Dann haben wir die tr()-Funktion auf unsere Texte angewendet. Diese Funktion ist notwendig, wenn Sie Ihre Applikation in mehreren Sprachen (z.B. in Englisch oder Chinesisch) anbieten möchten. Wir werden hier nicht weiter auf Details eingehen, aber Sie können dem Qt Linguist Link weiter unten folgen, um mehr Informationen zu erhalten.
h3. Weitere Informationen
tr() and internationalization: "Qt Linguist Handbuch&quot;:http://doc.qt.nokia.com/4.7/linguist-manual.html, "Übersetzbaren Code schreiben&quot;:http://doc.qt.nokia.com/4.7/i18n-source-translation.html, "Hallo tr()-Beispiel&quot;:http://doc.qt.nokia.com/4.7/linguist-hellotr.html, "Internationalisierung mit Qt&quot;:http://doc.qt.nokia.com/4.7/internationalization.html
* "QObjects&quot;:http://doc.qt.nokia.com/4.7/qtwebkit-bridge.html#qobjects und das Qt Objekt Modell (dies ist sehr wichtig, um Qt zu verstehen): "Objekt Modell&quot;:http://doc.qt.nokia.com/4.7/object.html
* qmake und das Qt Build System: "qmake Handbuch&quot;:http://doc.qt.nokia.com/4.7/qmake-manual.html

Eine .pro Datei erstellen

In diesem Beispiel schreiben wir unsere eigene .pro Datei, anstatt von qmake's project Option Gebrauch zu machen.


 HEADERS = notepad.h<br />SOURCES = notepad.cpp  main.cpp


p. Die folgenden Befehle erstellen das Beispiel-Projekt:


qmake<br />make


h2. Verwendung von QMainWindow
p. Für viele Anwendungen ist es von Vorteil, "QMainWindow&quot;:http://doc.qt.nokia.com/4.7/qmainwindow.html zu benutzen, da es sein eigenes Layout mitbringt, zu dem man eine Menüleiste, Andockende Widgets, Werkzeugleisten und eine Statusleiste hinzufügen kann. "QMainWindow&quot;:http://doc.qt.nokia.com/4.7/qmainwindow.html besitzt einen zentralen Bereich, der von jedem beliebigen Widget genutzt werden kann. In unserem Fall werden wir dort das Texteingabefeld platzieren.
Texteingabefeld in einem QMainWindow
p. Betrachten wir die neue Notepad-Klassendefinition:


 #include &lt;QtGui&amp;gt;
<br />class Notepad : public QMainWindow<br />{<br /> Q_OBJECT
<br /> public:<br /> Notepad();
<br /> private slots:<br /> void open();<br /> void save();<br /> void quit();
<br /> private:<br /> QTextEdit *textEdit;
<br /> QAction *openAction;<br /> QAction *saveAction;<br /> QAction *exitAction;
<br /> QMenu '''fileMenu;<br />};


p. Um ein Dokument speichern und öffnen zu können, fügen wir zwei neue Slots hinzu, die wir im nächsten Abschnitt implementieren.
p. Es kommt häufig vor, dass im Hauptfenster der selbe Slot von mehreren Widgets aufgerufen werden soll. Zum Beispiel von Menüeinträgen und Knöpfen auf einer Werkzeugleiste. Um das zu vereinfachen, bietet Qt die Klasse "QAction&quot;:http://doc.qt.nokia.com/4.7/qaction.html an, welche an mehrere Widgets übergeben, und an einen Slot gebunden werden können. Zum Beispiel können sowohl "QMenu&quot;:http://doc.qt.nokia.com/4.7/qmenu.html, als auch "QToolBar&quot;:http://doc.trolltech.com/4.7/qtoolbar.html Menüeinträge und Werkzeug-Knöpfe für die gleichen QActions anlegen. Wie das funktioniert sehen wir gleich.
p. Genau wie vorhin, nutzen wir den Konstruktor unserer Notepad-Klasse, um die GUI zu erstellen.


Notepad::Notepad()<br />{<br /> saveAction = new QAction(tr(&quot;&amp;Open&amp;quot;), this);<br /> saveAction = new QAction(tr(&quot;&amp;Save&amp;quot;), this);<br /> exitAction = new QAction(tr(&quot;E&amp;amp;xit&amp;quot;), this);
<br /> connect(openAction, SIGNAL (triggered()), this, SLOT (open()));<br /> connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));<br /> connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
<br /> fileMenu = menuBar()<s>&gt;addMenu(tr(&quot;&amp;File&amp;quot;));<br /> fileMenu</s>&gt;addAction(openAction);<br /> fileMenu-&gt;addAction(saveAction);<br /> fileMenu-&gt;addSeparator();<br /> fileMenu-&gt;addAction(exitAction);
<br /> textEdit = new QTextEdit;<br /> setCentralWidget(textEdit);
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}


p. "QAction&quot;:http://doc.qt.nokia.com/4.7/qaction.html werden mit dem Text erstellt, der auch in den Widgets erscheinen soll, zu denen wir sie hinzufügen (in userem Fall Menüeinträge). Wollten wir sie auch zu einer Werkzeugleiste hinzufügen, könnten wir für die Aktionen auch Icons festlegen.
p. Wenn nun einer der Menüeinträge ausgewählt wird, löst der Eintrag die Aktion aus und der daran gebundene Slot wird aufgerufen.
h3. Weitere Informationen
Hauptfenster und Hauptfenster-Klassen: "Hauptfenster von Anwendungen&quot;:http://doc.qt.nokia.com/4.7/mainwindow.html, "Hauptfenster Beispiele&quot;:http://doc.qt.nokia.com/4.7/examples-mainwindow.html
* MDI Anwendungen: "MDI Bereich&quot;:http://doc.qt.nokia.com/4.7/qmdiarea.html, "MDI Beispiele&quot;:http://doc.qt.nokia.com/4.7/mainwindows-mdi.html

h2. Speichern und Laden
p. Dieses Beispiel zeigt die Implementierung der Laden
und Speichern-Slots, die wir im vorigen Beispiel hinzugefügt haben.

Der Öffen-Dialog

Beginnen wir mit dem Öffnen-Slot

QString fileName = QFileDialog::getOpenFileName(this, tr(&quot;Open File&amp;quot;), &quot;&quot;, tr(&quot;Text Files ('''.txt);;C++ Files ('''.cpp *.h)&quot;));

if (fileName != &quot;&quot;) {<br /> QFile file&amp;amp;#40;fileName&amp;amp;#41;;<br /> if (!file.open(QIODevice::ReadOnly)) {<br /> QMessageBox::critical(this, tr(&quot;Error&amp;quot;), tr(&quot;Could not open file&amp;quot;));<br /> return;<br /> }<br /> QString contents = file.readAll().constData();<br /> textEdit-&gt;setPlainText(contents);<br /> file.close();<br />}

Im ersten Schritt wird der Anwender nach dem Namen der zu öffnenden Datei gefragt. Qt bietet dazu den "QFileDialog&quot;:http://doc.trolltech.com/4.7/qfiledialog.html, in dem der Nutzer eine Datei auswählen kann. Das Bild zeigt den Dialog unter Kubuntu. Die statische Funktion getOpenFileName() zeigt einen modalen Datei-Auswahl-Dialog der erst zur Hauptanwendung zurückkehrt, wenn der Anwender eine Datei ausgewählt, oder den Dialog geschlossen hat. Der Rückgabewert ist entweder der Pfad zur gewählten Datei, oder eine leere Zeichenkette, wenn der Nutzer den Dialog abgebrochen hat.

Nachdem wir überprüft haben, ob ein Dateipfad zurückgegeben wurde, versuchen wir die Datei mit der open()-Methode zu öffnen. Diese gibt den Wert true zurück, wenn die Datei erfolgreich geöffnet werden konnte. Wir werden an dieser Stelle nicht über Fehlerbehandlung sprechen, aber sie können den Links unter dem Eintrag "Weiterführende Informationen&quot; folgen. Konnte die Datei nicht geöffnet werden, verwenden wir "QMessageBox&quot;:http://doc.trolltech.com/4.7/qmessagebox.html, um den Fehler in einem Dialog an zu zeigen (weitere Details können Sie in der Klassenbeschreibung von "QMessageBox&quot;:http://doc.trolltech.com/4.7/qmessagebox.html nachlesen).

Das Lesen der Datei trivial. Wenn man die Funktion readAll() verwendet, wird der gesamte Inhalt der Datei in einem "QByteArray&quot;:http://doc.qt.nokia.com/4.7/qbytearray.html zurück liefert. Die Funktion constData() liefert alle Daten des Arrays als einen const char* Pointer zurück, wofür es in der QString Klasse einen Konstruktor gibt. Der Text kann dann im Textfeld angezeigt werden. Damit der Datei-Deskriptor wieder an das System zurück gegeben werden kann, schließen wir am Ende die Datei mit der close()-Methode

Lassen Sie uns jetzt mit dem Save() Slot weiter machen

QString fileName = QFileDialog::getSaveFileName(this, tr(&quot;Save File&amp;quot;), &quot;&quot;, tr(&quot;Text Files ('''.txt);;C++ Files ('''.cpp '''.h)&quot;));
<br />if (fileName != &quot;&quot;) {<br /> QFile file&amp;amp;#40;fileName&amp;amp;#41;;<br /> if (!file.open(QIODevice::WriteOnly)) {<br /> // error message<br /> } else {<br /> QTextStream stream(&amp;file);<br /> stream &lt;&lt; textEdit-&gt;toPlainText();<br /> stream.flush();<br /> file.close();<br /> }<br />}


p. Um den Inhalt des Textfeldes in eine Datei zu schreiben, benutzen wir die "QTextStream&quot;:http://doc.trolltech.com/4.7/qtextstream.html Klasse, welche das QFile-Objekt umhüllt. Der Text-Stream kann QStrings direkt in die Datei schreiben; "QFile&quot;:http://doc.trolltech.com/4.7/qfile.html aktzeptiert in der write()-Funktion von "QIODevice&quot;:http://doc.trolltech.com/4.7/qiodevice.html hingegen nur Rohdaten (char).

Weitere Informationen
* Dateien und EA-Geräte: "QFile&quot;:http://doc.qt.nokia.com/4.7/qfile.html, "QIODevice&quot;:http://doc.qt.nokia.com/4.7/qiodevice.html