Getting Started/de

From Qt Wiki
< Getting Started
Revision as of 13:20, 7 June 2015 by AdRay (talk | contribs) (Korrektur h3.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

diese Seite in: en, es, ru, pl, pt, nl


Schnelleinstieg in die Programmierung mit Qt

Willkommen in der Welt von Qt des plattformübergreifenden GUI Framework. In dieser "Schnelleinstiegs"-anleitung lehren wir grundlegendes Qt Wissen durch das Implementieren einer einfachen Notepad Anwendung. Nach dem Durchlesen dieser Anleitung sind Sie soweit in die Übersichten und API Dokumentation einzutauchen und die Informationen zu finden, die Sie für die Anwendung brauchen, die Sie entwickeln.

Hallo Notepad

In diesem ersten Beispiel werden wir ein einfaches Texteingabefeld erstellen und in einem Fenster auf dem Desktop anzeigen. Das stellt das einfachste Qt Programm mit einer Benutzeroberfläche dar.

Texteingabefenster

Hier ist der Code:

#include <QApplication>
#include <QTextEdit>

int main(int argc, char *argv[])
{
 QApplication app(argc, argv);

QTextEdit textEdit;
 textEdit.show();

return app.exec();
}

Lassen Sie uns mal Zeile für Zeile durch den Code gehen. In den ersten beiden Zeilen binden wir die Headerdateien für QApplication und QTextEdit ein, die beide Klassen darstellen, die wir für dieses Beispiel benötigen. Alle Qt Klassen haben eine Headerdatei, die den Namen der Klasse trägt.

Zeile 6 erstellt ein QApplication Objekt. Dieses Objekt behandelt anwendungsweit Ressourcen und ist notwendig für eine Qt Anwendung mit einer grafischen Benutzeroberfläche. Der Konstruktor benötigt argc und argv, weil Qt ein Paar Kommandozeilenargumente entgegen nehmen kann.

Zeile 8 erstellt ein QTextEdit Objekt. Eine Texteingabefeld ist ein visuelles Element einer Benutzeroberfläche. In Qt nennen wir solche Elemente Widgets. Beispiele anderer Widgets sind Scrollbalken, Labels und Radiobuttons. Ein Widget kann auch ein Container für andere Widgets sein; ein Dialog oder ein Hauptanwendungsfenster zum Beispiel.

Zeile 9 zeigt das Texteingabefeld auf dem Bildschirm in seinem eigenen Fenster. Da Widgets auch als Container verwendet werden können (z.B. ein QMainWindow, das Toolbars, Menüs, Statuszeile und ein paar andere Widgets), ist es möglich ein einzelnes Widget in eigenem Fenster anzuzeigen. Widgets sind standardmäßig nicht sichtbar; die Funktion show() macht sie sichtbar.

Zeile 11 lässt QApplication in die Ereignisschleife eintreten. Solange eine Qt Anwendung läuft werden Ereignisse generiert und an die Widgets der Anwendung gesendet. Beispiele solcher Ereignisse sind Mausklicks oder Tastatureingaben. Wenn Sie einen Text in das Texteingabefeld eintippen empfängt es Tastatureingabe Ereignisse und beantwortet diese in dem es den eingegebenen Text darstellt.

Um die Anwendung auszuführen öffnen Sie die Kommandozeile und gehen zum Verzeichnis in dem Sie die .cpp Dateien des Programms liegen haben. Folgende Shell Kommandos übersetzen und erstellen das Programm.

qmake -project
qmake
make

Das wird eine ausführbare Datei im part1 Verzeichnis erstellen (unter Windows werden Sie u. U. nmake anstatt make verwenden müssen. Ferner wird die ausführbare Datei in part1/debug oder part1/release erstellt). qmake is Qts Erstellprogramm, das eine Konfigurationsdatei entgegen nimmt. qmake erstellt diese für uns, wenn das Argument -project übergeben wird. Mit der Konfigurationsdatei (mit der Endung .pro) erstellt qmake eine make Datei, das das Programm für Sie erstellt. Wir werden uns später ansehen wie man eigene .pro Datei schreibt.

Mehr erfahren

|. Über |. Hier | | Widgets und Fenstergeometrie | Window and Dialog Widgets | | Ereignisse und ihre Behandlung | The Event System |

Einen Beenden Knopf hinzufügen

In einer echten Anwendung werden Sie mehr als nur ein Widget benötigen. Wir werden nun einen QPushButton unter das Texteingabefeld anbringen. Der Knopf wird die Notepad Anwendung beim Betätigen (z. B. durch das Klicken mit der Maus) beenden.

Eingabefeld mit Beenden Knopf

Lassen Sie uns mal einen Blick auf den Code werfen:

#include <QApplication>
#include <QLayout>
#include <QTextEdit>
#include <QPushButton>

int main(int argc, char *argv[])
{
 QApplication app(argc, argv);

 QTextEdit *textEdit = new QTextEdit;
 QPushButton *quitButton = new QPushButton("&Quit");

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

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

 QWidget window;
 window.setLayout(&layout);

 window.show();

 return app.exec();
}

Zeile 13 verwendet Qts Signals and Slots Mechanismus um die Anwendung beim Drücken des Beenden Knopf zu schließen. Ein Slot ist eine Funktion, die durch die Verwendung ihres Namens (in Form einer Zeichenkette) zu Laufzeit aufgerufen werden kann. Ein Signal ist eine Funktion die, wenn aufgerufen, alle dazu registrierten Slots aufruft; wir nennen es einen Slot mit einem Signal verbinden und ein Signal erzeugen.

quit() ist ein Slot der QApplication, der die Anwendung beendet. clicked() ist ein Signal, das QPushButton erzeugt, wenn der Knopf gedrückt wird. Die statische QObject::connect() Funktion sorgt für die Verbindung des Slots und des Signals. SIGNAL () und SLOT() sind zwei Makros, die die Funktionssignatur des Signal bzw. Slot entgegennehmen, die verbunden werden sollen. Ferner müssen wir die Zeiger der Objekte übergeben, das das Signal sendet bzw. empfängt.

Zeile 15 erzeugt ein QVBoxLayout. Wie bereits erwähnt, können Widgets auch andere Widgets enthalten. Es ist möglich die Abgrenzungen (Größe und Position) eines Kindwidgets direkt zu setzen. Jedoch ist es einfacher ein Layout zu verwenden. Ein Layout verwaltet die Abgrenzungen der Kindwidgets. Beispielsweise positioniert QVBoxLayout die Kindelemente vertikal untereinander.

Zeile 16 und 17 fügen das Texteingabefeld und den Knopf dem Layout hinzu. In Zeile 20 setzen wir das Layout eines Widgets.

Mehr erfahren

|. Über |. Hier | | Signale und Slots | Signals & Slots | | Layouts | Layout Management, Widgets and Layouts, Layout Examples | | Widgets die Qt bereitstellt | Qt Widget Gallery, Widget Examples |

QWidget Unterklassen erstellen

Wenn der Benutzer die Anwendung beenden will ist es u. U. erwünscht einen Dialog anzuzeigen, der sicherstellt, dass der Benutzer die Anwendung tatsächlich beenden möchte. In diesem Beispiel erstellen wir eine QWidget Unterklasse und fügen einen Slot der Klasse hinzu, den wir mit dem Beenden Knopf verknüpfen.

QWidget Unterklasse

Lassen Sie uns einen Blick auf den Code werfen:

#include <QWidget>
#include <QTextEdit>
#include <QPushButton>

class Notepad : public QWidget
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void quit();

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

Das Q_OBJECT Makro muss an erster Stelle einer Klassendefinition stehen; es deklariert unsere Klasse als QObject (natürlich muss sie auch vom QObject abgeleitet werden). Ein QObject reichert eine gewöhnlichen C++ Klasse mit einigen Fähigkeiten an. Beachtenswert ist die Möglichkeit den Klassen- und die Slotnamen zur Laufzeit abfragen zu können. Darüber hinaus ist es möglich die Parametertypen eines Slots abzufragen und den Slot aufzurufen.

Zeile 13 deklariert den Slot quit(). Einfach durch das Benutzen des Slot Makros. Der quit() Slot kann nun mit den Signalen verbunden werden, die eine passende Signatur besitzen (Jedes Signal, das keine Argumente erwartet).

Anstatt in der main() Funktion die Benutzeroberfläche zu erstellen und den Slot zu verbinden, benutzen wir Notepads Konstruktor.

#include "notepad.h"
#include <QApplication>

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"));
}
void Notepad::quit()
{
 qApp->quit();
}

Wie Sie in der Klassendefinition sehen konnten, benutzen wir Zeiger unserer QObjects (textEdit und quitButton). In der Regel sollten Sie QObjects Objekte immer auf dem Heap erstellen und diese nie kopieren.

Nun benutzen wir die tr() Funktion um unsere sichtbaren Bezeichner. Diese Funktion ist notwendig falls Sie vorhaben Ihre Anwendung in mehreren Sprachen (z. B. Englisch und Chinesisch) bereit zu stellen. Wir werden hier jedoch nicht ins Detail gehen. Sie können dem Qt Linguist Link folgen um mehr darüber zu erfahren.

Mehr erfahren

|. Über |. Hier | | tr() und Internationalisierung | Qt Linguist Manual, Writing Source Code for Translation, Hello tr() Example, Internationalization with Qt | | QObjects und das Qt Object Model (Essenziell um Qt zu verstehen) | Object Model | | qmake und das Qt Erstellungssystem | qmake Manual |

Eine .pro Datei erstellen

In diesem Beispiel erstellen wir unsere eigene .pro Datei, anstatt uns eine durch qmake -project Option generieren zu lassen.

HEADERS = notepad.h
SOURCES = notepad.cpp main.cpp

Die folgenden Kommandozeilen Kommandos erstellen die Beispielanwendung.

qmake
make

Die Verwendung eines QMainWindow

Viele Anwendungen werden durch die Verwendung von QMainWindow profitieren, das ihr eigenes Layout hat dem Sie eine Menüleiste, Dockwidgets, Werkzeugleisten und eine Statusleiste hinzufügen können. QMainWindow besitzt einen zentralen Bereich, der durch beliebiges Widget besetzt werden kann. In unserem Fall werden wir unser Texteingabefeld dort platzieren.

QMainWindow

Lassen Sie uns einen Blick auf die neue Notepad Klassendefinition werfen:

#include <QMainWindow>
#include <QTextEdit>
#include <QAction>
#include <QMenu>

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;
};

Wir fügen zwei weitere Slots hinzu, die ein Dokument speichern und schließen. Wir werden diese im nächsten Abschnitt implementieren.

In einem Hauptfenster soll der gleiche Slot oft mehrfach, durch verschiedene Widgets, aufgerufen werden können. Beispiele dafür sind Menüeinträge und Knöpfe in der Werkzeugleiste. Um dieses zu vereinfachen stellt Qt QAction bereit, die mehreren Widgets zugewiesen werden kann und mit einem Slot verbunden werden. Es können zum Beispiel sowohl QMenu als auch QToolBar Menüeinträge erzeugen unter Verwendung der gleichen QActions. Wir werden in Kürze sehen wie das funktioniert.

Wie zuvor benutzen wir Notepads Konstruktur um die Benutzeroberfläche zu erstellen.

#include "notepad.h"
#include <QMenuBar>

Notepad::Notepad()
{
 openAction = new QAction(tr("&Open"), this);
 saveAction = new QAction(tr("&Save"), this);
 exitAction = new QAction(tr("E&xit"), this);

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

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

 textEdit = new QTextEdit;
 setCentralWidget(textEdit);

 setWindowTitle(tr("Notepad"));
}

QActions werden mit dem Text erstellt, der auf dem Widget erscheinen soll, dem wir es zuweisen (in unserem Fall Menüeinträge). Falls wir sie zusätzlich auch einer Werkzeugleiste zuweisen wollten, hätten wir den Aktionen auch ein Icon zuweisen können.

Wenn nun ein Menüeintrag geklickt wird, löst der Eintrag die Aktion aus und der dazugehörige Slot wird aktiviert.

Mehr erfahren

|. Über |. Hier | | Hauptanwendungsfenster und Hauptfensterklassen | Application Main Window, Main Window Examples | | MDI applications | QMdiArea, MDI Example |

Speichern und Laden

In diesem Beispiel werden wir die Funktionalität der open() und save() Slots implementieren, die wir im vorherigen Beispiel eingeführt haben.

Öffnen Dialog

Wir werden mit dem open() Slot beginnen:

#include <QFileDialog>
#include <QMessageBox>
 
void Notepad::open()
{
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();
 }
}

Der erste Schritt ist den Benutzer nach dem Dateinamen der Datei zu fragen, die er öffnen möchte. Qt stellt dafür ein QFileDialog bereit, der einen Dialog darstellt in dem der Benutzer eine Datei auswählen kann. Das obere Bild zeigt den Dialog unter Kubuntu. Die statische getOpenFileName() Funktion zeigt einen modalen Dateidialog bis der Benutzer eine Datei ausgewählt hat. Es liefert den Dateipfad der ausgesuchten Datei zurück oder eine leere Zeichenkette, falls der Dialog abgebrochen wurde.

Sobald wir einen Dateinamen haben versuchen wir die Datei mittels open() zu öffnen. Die open() Funktion liefert true im Erfolgsfall. Wir werden hier nicht auf die Fehlerbehandlung eingehen, auf die mehr in den "Mehr erfahren" Verknüpfungen eingegangen wird. Im Fehlerfall benutzen wir QMessageBox um einen Dialog mit einer Fehlermeldung anzuzeigen (siehe die QMessageBox Klassen Beschreibung für weitere Details).

Es ist recht einfach die Daten mit der Funktion readAll() einzulesen, die alle Daten einer Datei in einem QByteArray zurück gibt. Die constData() Funktion gibt alle Daten in einem const char Array zurück, zu dem QString einen Konstruktor bereit stellt. Der Inhalt kann danach im Texteingabefeld angezeigt werden. Danach schließen wir die Datei mittels close() Funktion, um den Dateidescriptor an das Betriebssystem zu übergeben.

Lassen Sie uns nun zum save() Slot übergehen.

#include <QFileDialog>
#include <QTextStream>
 
void Notepad::save()
{
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(&file);
 stream << textEdit->toPlainText();
 stream.flush();
 file.close();
 }
}
}

Um den Inhalt des Texteingabefeldes zurück in die Datei zu schreiben verwenden wir die QTextStream Klasse, die das QFile Objekt umhüllt. Textstream kann QStrings direkt in eine Datei schreiben; QFile akzeptiert nur rohe Daten (char*) mit der write() Funktion des QIODevice.


#include <QApplication>
#include <QMessageBox>
 
void Notepad::quit()
{
 QMessageBox messageBox;
 messageBox.setWindowTitle(tr("Notepad"));
 messageBox.setText(tr("Do you really want to quit?"));
 messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
 messageBox.setDefaultButton(QMessageBox::No);
 
 if (messageBox.exec() == QMessageBox::Yes)
  qApp->quit();
}

main.cpp

#include "notepad.h"
#include <QApplication>
 
int main(int argc, char *argv[])
{
 QApplication app(argc, argv);
 
 Notepad notepad;
 notepad.show();
 
 return app.exec();
}


Mehr erfahren

|. Über |. Hier | | Dateien und E/A-Geräte | QFile, QIODevice | ===