000
20.12.2002, 20:16 Uhr
FloSoft
Medialer Over-Flow (Administrator)
|
Erstellt von Unbekannt In diesem Beitrag möchte ich euch die GUI-Programmierung unter Linux ein bisschen näher bringen. Hierbei werde ich allerdings nur auf die Qt-Bibliotheken eingehen, da sie sich aufgrund der Unterstützung des objektorientierten Programmierens meines Erachtens besonders gut zur Erstellung von graphischen Benutzeroberflächen (GUIs) eignen. Außerdem hat sich Qt in der Linuxprogrammierung schon fest eingebürgert und dient als Grundlage des KDE-Projekts.
Um GUI-Anwendungen unter Linux zu programmieren, benötigt ihr im Grunde nur einen C-Compiler und die Qt-Bibliotheken von Trolltech.
So, nun fangen wir gleich mal mit einem Minimalbeispiel an:
C++: |
#include <qapplication.h>
int main(int argc, char *argv[]) { QApplication app(argc, argv); int result = app.exec(); return result; }
|
Wenn ihr das Programm nun kompiliert habt und in der Konsole unter X ausführt, passiert offenbar "nichts". Es sieht sogar so aus, als ob das Programm in einer Endlosschleife laufen würde. Das ist auch fast richtig so. Also brechen wir das Programm lieber mit Strg+C ab, und ich erkläre alles der Reihe nach :-)
C++: |
#include <qapplication.h>
|
Diese Zeile inkludiert die Klasse QApplication. Jede Qt-Klasse ist in einer eigenen Headerdatei definiert, damit die Kompilierzeit verkürzt wird.
C++: |
int main(int argc, char *argv[])
|
Diese Zeile gleicht der normalen Konvention von C/C++ Programmen, mit der Ausnahme, dass wir für Qt unbedingt die Kommandozeilenparameter benötigen.
C++: |
QApplication app(argc, argv);
|
Eine lokale Instanz der Klasse QApplication wird erzeugt und mit den Parametern der "main()"-Funktion initialisiert. Die Klasse QApplication muss in jedem Qt-Projekt einmal enthalten sein. Sie stellt das zentrale Kontrollobjekt des Programmes dar. Es regelt die Verbindung zum X-Server und ist für die Event-Kontrolle verantwortlich.
C++: |
int result = app.exec();
|
In dieser Zeile wird nun die Methode "exec()" der Klasse QApplication aufgerufen. Diese Methode ist dafür verantwortlich, dass sich unser Programm in einer Endlosschleife befindet, da sie nun alle Ereignisse der X-Servers entgegennimmt, und das Programm erst dann beendet, wenn die Methode "quit()" der Klasse QApplication aufgerufen wird.
Das Programm wird wie jedes andere C-Programm auch beendet und der Wert von "result" den die Methode "exec()" zurückgeliefert hat, an das Betriebsystem übergeben.
Damit unser Programm auch dem Anspruch einer GUI-Anwendung gerecht wird, bauen wir nun einfach eine Kommunikationsschnittstelle zum Benutzer ein, z.B. einen Knopf, der das Programm beendet, sobald er gedrückt wird.
C++: |
#include <qapplciation.h> #include <qpushbutton.h> <em>// Aha, war es nicht so, dass jede Qt-Klasse in einer eigenen Headerdatei definiert ist? :-)</em>
int main(int argc, char *argv[])
QApplication app(argc,argv);
QPushButton *b = new QPushButton("Klick mich!", 0);
|
Wir erzeugen also einfach einen QPushButton auf dem Stack mit der Aufschrift "Klick mich!". Der zweite Parameter gibt das "Vater-Widget", dem der Button zugeordnet sein soll, an. Da aber unser Knopf das einzige Widget sein soll, hat es keine übergeordneten Widgets und somit als zweiten Parameter 0. (Bemerkung: Ein Widget ist nichts anderes, als ein "Trägerobjekt" für graphische Elemente, bzw. ein graphisches Objekt selbst.)
C++: |
QObject::connect(b, SIGNAL(clicked()), &app,SLOT (quit()));
|
So, nun kommen wir zu einer "Eigenheit" der Qt-Bibliothek. Da die Sprachmittel von C++ den Entwicklern nicht ausreichten, habe sie das Signal-Slot-Prinzip erfunden. Hierbei reagiert eine Slot-Funktion auf eine SIGNAL-Funktion. Die Zeile sagt uns also: Wenn Knopf *b gedrückt wird, d.h. wenn er das "SIGNAL clicked()" verschickt, dann soll die Funktion "quit()" des QApplication-Objektes aufgerufen werden. Das hat zur Folge, dass sich unser Programm beim Anklicken des Knopfes beendet :-)
Oh nein, schon wieder ne neue Methode? Richtig! Wenn wir nicht die "show()"-Methode des Hauptwidgets aufrufen würden, dann würde nichts am Bildschirm zu sehen sein. Auf dem Stack erzeugte Objekte und deren Kinder-Widgets werden erst durch die Methode "show()" dem Benutzer sichtbar.
C++: |
int result = app.exec(); return result;
|
So, jetzt hast du schon mal das Wichtigste verstanden. Da aber ein einzelner Knopf ein bisschen langweilig ist, beschreibe ich noch mal ein etwas schwierigeres Beispiel:
C++: |
#include <qapplication.h> #include <qpushbutton.h> #include <qlayout.h> #include <qmultilinedit.h>
int main(int argc, char *argv[]) { QApplication app(argc,argv); QWidget *mw = new QWidget();
QMultiLineEdit *m = new QMultiLineEdit(mw); QPushButton *c = new QPushButton("Clear", mw) QObject::connect(c,SIGNAL(clicked()),m,SLOT(clear())); QPushButton *q = new QPushButton("Quit", mw); QObject::connect(q,SIGNAL(clicked()),&app,SLOT(quit()));
QVBoxLayout *tl = new QVBoxLayout(mw); QHBoxLayout *bl = new QHBoxLayout();
tl->addWidget(m); bl->addWidget(c); bl->addWidget(q); tl->addLayout(bl);
mw->setCaption("Titelleiste"); mw->show();
int result = app.exec(); return result; }
|
Puh.... und nun die Besprechung:
C++: |
#include <qapplication.h> #include <qpushbutton.h> #include <qlayout.h> #include <qmultilinedit.h>
|
Außer dass wir 2 zusätzliche Headerdateien inkludieren, gibt es hier nichts Neues. "qlayout.h" stellt Klassen zum Layouten zur Verfügung und "qmultilinedit.h" ein einfaches Textfeld.
C++: |
int main(int argc, char *argv[]) { QApplication app(argc,argv); QWidget *mw = new QWidget();
|
So, die erste Zeile dürften klar sein, wenn nicht, dann lest nochmal den ersten Teil des Tutorials. In der 2. Zeile schließlich erkennt der erfahrene Programmierer, dass ein stinknormales, schmuckloses Vater-Widget erzeugt wird. Dies soll also das Hauptwidget zu sein.
C++: |
QMultiLineEdit *m = new QMultiLineEdit(mw); QPushButton *c = new QPushButton("Clear", mw); QObject::connect(c,SIGNAL(clicked()),m,SLOT(clear())); QPushButton *q = new QPushButton("Quit", mw); QObject::connect(q,SIGNAL(clicked()),&app,SLOT(quit()));
|
Hier erzeugen wir 3 Kind-Widgets (*m, *c, *q), mit *mw als Vater-Widget. Die Signale der Buttons werden, damit sie später auch irgend einen Nutzen haben, mit Slots der Hauptfunktion (app) und des Editierfeldes (*m) verbunden.
C++: |
QVBoxLayout *tl = new QVBoxLayout(mw); QHBoxLayout *bl = new QHBoxLayout();
|
Jetzt kommt das eigentlich Neue an diesem Programmbeispiel. Wir müssen ein Layout bestimmen, damit das Programm benutzbar wird. Wir erstellen also zuerst ein Layout, welches die Elemente in vertikaler Reihe anordnet. Dieses Layout bekommt als Vater-Widget *mw zugewiesen. Dann erzeugen wir ein horizontales Layout, welches Elemente in horizontaler Reihe anordnet, diesmal aber ohne Vater-Widget. Warum, das werden wir gleich noch sehen...
C++: |
tl->addWidget(m); bl->addWidget(c); bl->addWidget(q); tl->addLayout(bl);
|
Hier nämlich ordnen wir dem vertikalem Layout, welches das Hauptwidget als Vater hat, als erstes das Editierfeld zu. In der vierten Zeile wird zusätzlich das horizontale Layout, welches in horizontaler Richtung die beiden Knöpfe in Zeile 2 und 3 zugeordnet bekommen hat, dem vertikalen Layout zugeordnet.
C++: |
mw->setCaption("Titelleiste");
|
Jetzt legen wir einfach noch die Bezeichnung des Programmes in der Titelleiste fest, hier also "Titelleiste".
Damit auch was angezeigt wird. ;-)
C++: |
int result = app.exec(); return result;
|
Und das kennen wir ja schon :-)
Das war's erst mal... Wenn ihr Fragen habt, postet doch einfach ins
C/C++ - Forum.
Weitere Informationen zu Qt gibt's auch direkt bei Trolltech:
Qt Reference Documentation. -- class God : public ChuckNorris { }; Dieser Post wurde am 06.07.2003 um 15:29 Uhr von FloSoft editiert. |