Archiv/Qt5/Beispiele

Archivierte Anleitung

Dieser Artikel wurde archiviert. Das bedeutet, dass er nicht mehr auf Richtigkeit überprüft oder anderweitig gepflegt wird. Der Inhalt wurde für keine aktuell unterstützte Ubuntu-Version getestet. Wenn du Gründe für eine Wiederherstellung siehst, melde dich bitte in der Diskussion zum Artikel. Bis dahin bleibt die Seite für weitere Änderungen gesperrt.

Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:

  1. ⚓︎ Ein Terminal öffnen

  2. ⚓︎ Pakete aus dem Quellcode erstellen

  3. ⚓︎ QtCreator (optional)

Inhaltsverzeichnis
  1. QCoreApplication C++
    1. Klasse Ausgabe
      1. ausgabe.h
      2. ausgabe.cpp
    2. main.cpp
    3. Kompilieren
      1. ausgabe.pro
    4. Ausführung
  2. QtQuick/QML
    1. main.cpp
    2. main.qml
      1. qml.qrc
    3. Kompilierung
  3. Python / PySide
    1. Projektdatei
  4. Links

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:

Befehl zum Installieren der Pakete:

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:

Befehl zum Installieren der Pakete:

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"]
}