Beispiele
Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:
Ubuntu 20.10 Groovy Gorilla
Du möchtest den Artikel für eine weitere Ubuntu-Version testen? Mitarbeit im Wiki ist immer willkommen! Dazu sind die Hinweise zum Testen von Artikeln zu beachten.
Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:
Dies sind die Beispiele zum Hauptartikel Qt5. QCoreApplication zeigt ein einfaches Signal&Slot-Beispiel, QML ein einfaches Layout im „Hello World“-Stil mit einer separaten Schaltfläche zum Beenden. Ein PySide-Beispiel zeigt die simple Verwendung eines Labels.
QCoreApplication C++¶
Dieses Beispiel zeigt die Verwendung des Signal&Slot-Konzeptes, so wie die Handhabung der Meldungen mit den Qt-eigenen Methoden über QDebug in einer schlichten Konsolenanwendung.
Klasse Ausgabe¶
ausgabe.h¶
Es wird das Q_OBJECT-Makro verwendet, um die Klasse dem Qt-Objekt-System bekannt zu machen. Eine solche Klasse muss von QObject oder einer Kindklasse abgeleitet werden, um das Signal&Slot-Konzept verwenden zu können.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ifndef AUSGABE_H #define AUSGABE_H #include <QObject> class Ausgabe : public QObject { Q_OBJECT public: Ausgabe( QObject *parent = nullptr ); public slots: void los(); // eigenen Slot definieren signals: void fertig(); // Eigenes Signal ohne Argumente }; #endif // AUSGABE_H |
ausgabe.cpp¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include "ausgabe.h" #include <QDebug> //______________________________________________________________________________ Ausgabe::Ausgabe( QObject *parent ) : QObject( parent ) { } //______________________________________________________________________________ // Unser Slot wird als normale C++-Funktion implementiert: void Ausgabe::los() { qDebug() << "Debug-Nachricht"; qInfo() << "Hallo Welt!"; qCritical() << "Fehlermeldung!"; emit fertig(); // Signal senden } //______________________________________________________________________________ // Das Signal wird nicht implementiert! |
main.cpp¶
Hinweis:
Um eine Verbindung ohne Objektinstanz zu ermöglichen, kann das statische QObject::connect
verwendet werden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <QtCore> #include <QDebug> #include "ausgabe.h" int main( int argc, char **argv ) { QCoreApplication a( argc, argv ); // Initialisierung des „main event loops“ qDebug() << "Initialisiere Ausgabe…"; // Die Klasse Ausgabe wird als Kind der CoreApplication auf dem Heap initialisiert, // so dass die Instanz beim Beenden automatisch gelöscht wird. Ausgabe *ausgabe = new Ausgabe( &a ); // Signale und Slots: Verbinden der quit()-Methode mit der Klasse // Der main loop wird verlassen und das Programm beendet, sobald // das Signal „fertig“ empfangen wird. quit() ist ein Standard-Slot a.connect( ausgabe, &Ausgabe::fertig, &a, &QCoreApplication::quit ); // Alternative Schreibweise mit Makros: a.connect( ausgabe, SIGNAL( fertig() ), &a, SLOT( quit() ) ); // Man kann die Slot-Methoden auch ohne Verbindung ähnlich eines callbacks // verwenden: QTimer::singleShot( 0, ausgabe , SLOT( los() ) ); return a.exec(); // Mit Exit-Code der CoreApplication beenden } |
Kompilieren¶
ausgabe.pro¶
Erstellt man die Datei mit dem QtCreator, sieht diese etwa so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | QT -= gui CONFIG += c++11 console CONFIG -= app_bundle # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ ausgabe.cpp \ main.cpp # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target HEADERS += \ ausgabe.h |
Die Projektdatei kann aber auch per qmake
automatisch generiert werden:
qmake -project
Resultat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ###################################################################### # Automatically generated by qmake (3.1) Mon Dec 7 16:53:24 2020 ###################################################################### TEMPLATE = app TARGET = Ausgabe INCLUDEPATH += . # You can make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # Please consult the documentation of the deprecated API in order to know # how to port your code away from it. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 # Input HEADERS += ausgabe.h SOURCES += ausgabe.cpp main.cpp |
Anschließend kann das Projekt mit
qmake && make
kompiliert werden.
Ausführung¶
Wird das Programm im Terminal ausgeführt, so erhält man die Ausgaben
Initialisiere Ausgabe… Debug-Nachricht Hallo Welt! Fehlermeldung!
Beim grafischen Start — bspw. per .desktop-Datei oder im QtCreator — erhält man keine sichtbare Ausgabe. Da Qt so konzipiert ist, dass solche Nachrichten nicht verloren gehen, werden die Meldungen entsprechend ihrer Art an das Betriebssystem weitergegeben. journalctl -xe
sieht dann bspw. wie folgt aus:
Dec 07 16:56:54 desktop Ausgabe[6838]: Initialisiere Ausgabe… Dec 07 16:56:54 desktop Ausgabe[6838]: Debug-Nachricht Dec 07 16:56:54 desktop Ausgabe[6838]: Hallo Welt! Dec 07 16:56:54 desktop Ausgabe[6838]: Fehlermeldung!
Di Die Ausgabe im System erfolgt farbig, je nach Typ der Meldung, dies ist hier nicht dargestellt.
Hinweis:
Um die Ausgaben bei einer GUI-Anwendung im Terminal zu sehen, kann die Option CONFIG += console
in der Projektdatei verwendet werden.
QtQuick/QML¶
Mit Hilfe von QtQuick lassen sich recht schnell Benutzeroberflächen erstellen. Es gibt mehrere Möglichkeiten mit QML zu Arbeiten, hier soll ein einfaches „Hello-World“-Beispiel in QtQuick reichen.
main.cpp¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { // Unterstützung für hochauflösende Geräte: QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // Der „main event loop“ QGuiApplication app(argc, argv); // die QML-Engine bietet die Grundlagen für die Darstellung mittels QML // Beim Kompilieren wird der QML-Code zu C++ übersetzt QQmlApplicationEngine engine; // Die QML-Datei wird per Ressource eingebunden. Das erlaubt das einkompilieren. // Wäre die Angabe per file://, würde lediglich die Engine einkompiliert und die // QML-Dateien zur Laufzeit auswerten const QUrl url(QStringLiteral("qrc:/main.qml")); // Verbindung der Signale, inkl. Fehlerbehandlung // Dies stellt sicher, dass die Engine die Anwendung mit Fehler beendet, // wenn die QMLEngine die Datei nicht laden/finden/verarbeiten kann QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); // laden der main.qml return app.exec(); // Ergebnis des main loops } |
main.qml¶
import QtQuick 2.12 import QtQuick.Window 2.12 // Window import QtQuick.Controls 2.0 // Button Window { width: row.width height: ende.height visible: true title: "ubuntuusers.de" Row{ id: row height: ende.height Text { padding: font.pointSize text: "Hallo QML!" } Button { id: ende text: "Ende" onReleased: Qt.quit() } } }
qml.qrc¶
Eine Ressource-Datei ist eine XML-Datei, die entsprechende Verweise auf einzubettende Elemente liefert. So können bspw. auch das Anwendungs-Icon oder SQL-Routinen in die ausführbare Datei einkompiliert werden und müssen nicht im Zielsystem in Ordner einsortiert werden oder gegen Manipulation geschützt.
<RCC> <qresource prefix="/"> <file>main.qml</file> </qresource> </RCC>
Kompilierung¶
Für das folgende Beispiel werden zusätzliche Pakete benötigt:
qtdeclarative5-dev
Paketliste zum Kopieren:
sudo apt-get install qtdeclarative5-dev
Oder mit apturl installieren, Link: apt://qtdeclarative5-dev
Es gelten die gleichen Regeln, wie im C++-Beispiel, daher wird hier die gekürzte Ausgabe verwendet:
1 2 3 4 5 6 | QT += quick TEMPLATE = app TARGET = AusgabeQML INCLUDEPATH += . SOURCES += main.cpp qml RESOURCES += qml.qrc |
Wichtig ist die Resource-Datei als solche zu kennzeichnen, damit das Einkompilieren funktioniert, so wie die Option für QtQuick zu setzen. Das generieren der Projektdatei funktioniert mit folgendem Aufruf:
qmake -project QT+=quick .
Anschliessend wird wieder qmake && make
verwendet.
Python / PySide¶
Zusätzlich nötige Pakete für dieses Beispiel:
python3-pyside2.qtcore (universe/python)
python3-pyside2.qtwidgets (universe/python)
Paketliste zum Kopieren:
sudo apt-get install python3-pyside2.qtcore python3-pyside2.qtwidgets
Oder mit apturl installieren, Link: apt://python3-pyside2.qtcore,python3-pyside2.qtwidgets
Ein einfaches Beispiel unter Verwendung von PySide2. Als Projektname wurde AusgabePython.py gewählt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/python3 import sys from PySide2.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout class AusgabePython(QWidget): def __init__(self): QWidget.__init__(self) label = QLabel(self) label.setText('ubuntuusers.de sagt:\n\t"Hallo Python!"') lay = QVBoxLayout() lay.addWidget(label) self.setLayout(lay) if __name__ == "__main__": app = QApplication([]) window = AusgabePython() window.show() sys.exit(app.exec_()) |
Projektdatei¶
Eine Projektdatei wird bei Python nicht benötigt. Im Vergleich zu den C++-Ansätzen listet diese unter Verwendung des QtCreators nur enthaltene Dateien auf:
1 2 3 | { "files": ["AusgabePython.py"] } |
Links¶
Qt5 Hauptartikel