Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

Getting Started with Qt/de: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 9: Line 9:
[[Image:http://doc.qt.nokia.com/4.7/images/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 /><code>#include &lt;QApplication&amp;gt;<br />#include &lt;QTextEdit&amp;gt;
Und hier ist der zugehörige Quellcode:
<code>#include <QApplication>
#include <QTextEdit>


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


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


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.
Gehen wir nun den Code Schritt für Schritt durch. In den ersten beiden Zeilen werden die Header-Dateien für "QApplication":http://doc.trolltech.com/4.7/qapplication.html und "QTextEdit":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 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.
Line 23: Line 30:
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 &quot;Taste gedrückt&amp;quot;-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 "Taste gedrückt"-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:
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:


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


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.
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.


=== Weitere Informationen ===
=== Weitere Informationen ===


* Widgets und Fenstergeometrie: &quot;Fenster und Dialog-Widgets&amp;quot;:http://doc.qt.nokia.com/4.7/application-windows.html
* Widgets und Fenstergeometrie: "Fenster und Dialog-Widgets":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
* Ereignisse und Ereignisbehandlung: "Das Ereignis-System":http://doc.qt.nokia.com/4.7/eventsandfilters.html


== Hinzufügen eines Beenden-Knopfes ==
== Hinzufügen eines Beenden-Knopfes ==


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).
In einer realen Anwendung wird normalerweise mehr benötigt, als ein einzelnes Widget. Daher werden wir nun einen "QPushButton":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).


[[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|Ein Knopf zum Beenden der Anwendung]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|Ein Knopf zum Beenden der Anwendung]]


Werfen wir zunächst einen Blick auf den Code:<br /><code>#include &lt;QtGui&amp;gt;
Werfen wir zunächst einen Blick auf den Code:
<code>#include <QtGui>


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


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


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


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


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


window.show();
window.show();


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


In '''Zeile 1''' wird der Header QtGui eingebunden, der alle GUI Klassen in Qt enthält.
In '''Zeile 1''' wird der Header QtGui eingebunden, der alle GUI Klassen in Qt enthält.
Line 64: Line 82:
'''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.
'''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 &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 12''' wird ein "QVBoxLayout":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.
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.
Line 70: Line 88:
=== Weitere Informationen ===
=== Weitere Informationen ===


* Signale und Slots: &quot;Signals &amp; Slots&amp;quot;:http://doc.qt.nokia.com/4.7/signalsandslots.html
* Signale und Slots: "Signals &amp; Slots":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
* Layouts: "Layout Management":http://doc.qt.nokia.com/4.7/layout.html, "Widgets and Layouts":http://doc.qt.nokia.com, "Layout Beispiele":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
* In Qt enthaltene Widgets: "Qt Widget Gallerie":http://doc.qt.nokia.com/4.7/gallery.html, "Widget Beispiele":http://doc.qt.nokia.com/4.7/examples-widgets.html


== Von QWidget ableiten ==
== Von QWidget ableiten ==
Line 80: Line 98:
[[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|Von QWidget ableiten]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|Von QWidget ableiten]]


Schauen wir uns den Code an<br /><code>class Notepad : public QWidget<br />{<br /> Q_OBJECT
Schauen wir uns den Code an
<code>class Notepad : public QWidget
{
Q_OBJECT


public:<br /> Notepad();
public:
Notepad();


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


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


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.
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.
Line 94: Line 120:
Anstatt in der main()-Funktion die GUI zu erstellen und den Slot zu verbinden, nutzen wir nun den Konstruktor der Notepad-Klasse.
Anstatt in der main()-Funktion die GUI zu erstellen und den Slot zu verbinden, nutzen wir nun den Konstruktor der Notepad-Klasse.


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


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


QVBoxLayout '''layout = new QVBoxLayout;<br /> layout-&gt;addWidget(textEdit);<br /> layout-&gt;addWidget(quitButton);
QVBoxLayout '''layout = new QVBoxLayout;
<br /> setLayout(layout);
layout->addWidget(textEdit);
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}</code>
layout->addWidget(quitButton);
<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.
setLayout(layout);
<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
 
setWindowTitle(tr("Notepad"));
}</code>
 
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":http://doc.qt.nokia.com/4.7/linguist-manual.html, "Übersetzbaren Code schreiben":http://doc.qt.nokia.com/4.7/i18n-source-translation.html, "Hallo tr()-Beispiel":http://doc.qt.nokia.com/4.7/linguist-hellotr.html, "Internationalisierung mit Qt":http://doc.qt.nokia.com/4.7/internationalization.html
* "QObjects":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":http://doc.qt.nokia.com/4.7/object.html
* qmake und das Qt Build System: "qmake Handbuch":http://doc.qt.nokia.com/4.7/qmake-manual.html


== Eine .pro Datei erstellen ==
== Eine .pro Datei erstellen ==


In diesem Beispiel schreiben wir unsere eigene .pro Datei, anstatt von qmake's <s>project Option Gebrauch zu machen.
In diesem Beispiel schreiben wir unsere eigene .pro Datei, anstatt von qmake'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:
<code> HEADERS = notepad.h
<br /><code>qmake<br />make</code>
SOURCES = notepad.cpp  main.cpp</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.
p. Die folgenden Befehle erstellen das Beispiel-Projekt:
<br />[[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|Texteingabefeld in einem QMainWindow]]
 
<br />p. Betrachten wir die neue Notepad-Klassendefinition:
<code>qmake
<br /><code> #include &lt;QtGui&amp;gt;
make</code>
<br />class Notepad : public QMainWindow<br />{<br /> Q_OBJECT
 
<br /> public:<br /> Notepad();
h2. Verwendung von QMainWindow
<br /> private slots:<br /> void open();<br /> void save();<br /> void quit();
 
<br /> private:<br /> QTextEdit *textEdit;
p. Für viele Anwendungen ist es von Vorteil, "QMainWindow":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":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 /> QAction *openAction;<br /> QAction *saveAction;<br /> QAction *exitAction;
 
<br /> QMenu '''fileMenu;<br />};</code>
[[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|Texteingabefeld in einem QMainWindow]]
<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.
p. Betrachten wir die neue Notepad-Klassendefinition:
<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);
<code> #include <QtGui>
<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);
class Notepad : public QMainWindow
<br /> textEdit = new QTextEdit;<br /> setCentralWidget(textEdit);
{
<br /> setWindowTitle(tr(&quot;Notepad&amp;quot;));<br />}</code>
Q_OBJECT
<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.
public:
<br />h3. Weitere Informationen
Notepad();
<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
private slots:
<br />p. Dieses Beispiel zeigt die Implementierung der Laden</s> und Speichern-Slots, die wir im vorigen Beispiel hinzugefügt haben.
void open();
void save();
void quit();
 
private:
QTextEdit *textEdit;
 
QAction *openAction;
QAction *saveAction;
QAction *exitAction;
 
QMenu '''fileMenu;
};</code>
 
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":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":http://doc.qt.nokia.com/4.7/qmenu.html, als auch "QToolBar":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.
 
<code>Notepad::Notepad()
{
saveAction = new QAction(tr("&amp;Open"), this);
saveAction = new QAction(tr("&amp;Save"), this);
exitAction = new QAction(tr("E&amp;amp;xit"), this);
 
connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
 
fileMenu = menuBar()->addMenu(tr("&amp;File"));
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
 
textEdit = new QTextEdit;
setCentralWidget(textEdit);
 
setWindowTitle(tr("Notepad"));
}</code>
 
p. "QAction":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":http://doc.qt.nokia.com/4.7/mainwindow.html, "Hauptfenster Beispiele":http://doc.qt.nokia.com/4.7/examples-mainwindow.html
* MDI Anwendungen: "MDI Bereich":http://doc.qt.nokia.com/4.7/qmdiarea.html, "MDI Beispiele":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.


[[Image:http://doc.qt.nokia.com/4.7/images/gs5.png|Der Öffen-Dialog]]
[[Image:http://doc.qt.nokia.com/4.7/images/gs5.png|Der Öffen-Dialog]]
Line 141: Line 234:
Beginnen wir mit dem Öffnen-Slot
Beginnen wir mit dem Öffnen-Slot


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


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>
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
}
QString contents = file.readAll().constData();
textEdit->setPlainText(contents);
file.close();
}</code>


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.
Im ersten Schritt wird der Anwender nach dem Namen der zu öffnenden Datei gefragt. Qt bietet dazu den "QFileDialog":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 &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).
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 "QMessageBox":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":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 &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
Das Lesen der Datei trivial. Wenn man die Funktion '''readAll()''' verwendet, wird der gesamte Inhalt der Datei in einem "QByteArray":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


<code>QString fileName = QFileDialog::getSaveFileName(this, tr(&quot;Save File&amp;quot;), &quot;&quot;, tr(&quot;Text Files ('''.txt);;C++ Files ('''.cpp '''.h)&quot;));
<code>QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Text Files ('''.txt);;C++ Files ('''.cpp '''.h)"));
<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>
 
<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''').
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
// error message
} else {
QTextStream stream(&amp;file);
stream << textEdit->toPlainText();
stream.flush();
file.close();
}
}</code>
 
p. Um den Inhalt des Textfeldes in eine Datei zu schreiben, benutzen wir die "QTextStream":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":http://doc.trolltech.com/4.7/qfile.html aktzeptiert in der write()-Funktion von "QIODevice":http://doc.trolltech.com/4.7/qiodevice.html hingegen nur Rohdaten (char''').


=== 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 ===
=== Weitere Informationen
* Dateien und EA-Geräte: "QFile":http://doc.qt.nokia.com/4.7/qfile.html, "QIODevice":http://doc.qt.nokia.com/4.7/qiodevice.html ===

Revision as of 09:57, 25 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 <QApplication>
#include <QTextEdit>

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

return app.exec();
}

Gehen wir nun den Code Schritt für Schritt durch. In den ersten beiden Zeilen werden die Header-Dateien für "QApplication":http://doc.trolltech.com/4.7/qapplication.html und "QTextEdit":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"-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
qmake
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" 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":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 <QtGui>

int main(int argv, char **args)
{
 QApplication app(argv, args);

QTextEdit textEdit;
 QPushButton quitButton("Quit");

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

QVBoxLayout layout;
 layout.addWidget(&amp;textEdit);
 layout.addWidget(&amp;quitButton);

QWidget window;
 window.setLayout(&amp;layout);

window.show();

return app.exec();
}

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":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
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void quit();

private:
 QTextEdit *textEdit;
 QPushButton *quitButton;
 };

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()
{
 textEdit = new QTextEdit;
 quitButton = new QPushButton(tr("Quit"));

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

QVBoxLayout '''layout = new QVBoxLayout;
 layout->addWidget(textEdit);
 layout->addWidget(quitButton);

 setLayout(layout);

 setWindowTitle(tr("Notepad"));
}

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":http://doc.qt.nokia.com/4.7/linguist-manual.html, "Übersetzbaren Code schreiben":http://doc.qt.nokia.com/4.7/i18n-source-translation.html, "Hallo tr()-Beispiel":http://doc.qt.nokia.com/4.7/linguist-hellotr.html, "Internationalisierung mit Qt":http://doc.qt.nokia.com/4.7/internationalization.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
SOURCES = notepad.cpp  main.cpp

p. Die folgenden Befehle erstellen das Beispiel-Projekt:

qmake
make

h2. Verwendung von QMainWindow

p. Für viele Anwendungen ist es von Vorteil, "QMainWindow":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":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 <QtGui>

class Notepad : public QMainWindow
{
 Q_OBJECT

 public:
 Notepad();

 private slots:
 void open();
 void save();
 void quit();

 private:
 QTextEdit *textEdit;

 QAction *openAction;
 QAction *saveAction;
 QAction *exitAction;

 QMenu '''fileMenu;
};

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":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":http://doc.qt.nokia.com/4.7/qmenu.html, als auch "QToolBar":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()
{
 saveAction = new QAction(tr("&amp;Open"), this);
 saveAction = new QAction(tr("&amp;Save"), this);
 exitAction = new QAction(tr("E&amp;amp;xit"), this);

 connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
 connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
 connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));

 fileMenu = menuBar()->addMenu(tr("&amp;File"));
 fileMenu->addAction(openAction);
 fileMenu->addAction(saveAction);
 fileMenu->addSeparator();
 fileMenu->addAction(exitAction);

 textEdit = new QTextEdit;
 setCentralWidget(textEdit);

 setWindowTitle(tr("Notepad"));
}

p. "QAction":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":http://doc.qt.nokia.com/4.7/mainwindow.html, "Hauptfenster Beispiele":http://doc.qt.nokia.com/4.7/examples-mainwindow.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("Open File"), "", tr("Text Files ('''.txt);;C++ Files ('''.cpp *.h)"));

if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::ReadOnly)) {
 QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
 return;
 }
 QString contents = file.readAll().constData();
 textEdit->setPlainText(contents);
 file.close();
}

Im ersten Schritt wird der Anwender nach dem Namen der zu öffnenden Datei gefragt. Qt bietet dazu den "QFileDialog":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 "QMessageBox":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":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":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("Save File"), "", tr("Text Files ('''.txt);;C++ Files ('''.cpp '''.h)"));

if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::WriteOnly)) {
 // error message
 } else {
 QTextStream stream(&amp;file);
 stream << textEdit->toPlainText();
 stream.flush();
 file.close();
 }
}

p. Um den Inhalt des Textfeldes in eine Datei zu schreiben, benutzen wir die "QTextStream":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":http://doc.trolltech.com/4.7/qfile.html aktzeptiert in der write()-Funktion von "QIODevice":http://doc.trolltech.com/4.7/qiodevice.html hingegen nur Rohdaten (char).

=== Weitere Informationen