Evgenii Legotckoi
Evgenii Legotckoi4. November 2019 05:15

QML - Tutorial 036. Arbeiten mit Signalen und Slots in QML

Dieser Artikel ist die vollständigste Beschreibung von Signalen und Slots in QML im Vergleich zu allen vorherigen Artikeln auf dieser Seite.

In diesem Artikel werde ich versuchen, Folgendes zu erklären, wenn ich mit Qt/QML + Qt/C++ arbeite:

  • Möglichkeiten, Signale und Slots zu deklarieren, die in einer C++-Klasse auch Methoden genannt werden, um in der QML-Schicht registriert zu werden
  • Verbindungswege zu den Signalen von Klassen, die in C++ als Kontext deklariert sind
  • Arbeite mit Q_PROPERTY, was ebenfalls Signale und Slots benötigt
  • Möglichkeiten, Signale und Slots in QML zu verbinden
  • usw.

Signale und Slots aus einer C++-Klasse

Lassen Sie uns unsere erste Klasse erstellen, die mit Signalen und Slots in QML funktioniert. Dies ist eines der allerersten Beispiele, die ich bereits gezeigt habe, aber ich werde dieses Beispiel wiederholen, um den Artikel so vollständig wie möglich zu machen.

In diesem Beispiel möchte ich eine Anwendung mit einer Schaltfläche erstellen, und das Drücken dieser Schaltfläche erhöht einen Zähler, der sich in einer C++-Klasse befindet. Diese C++-Klasse wird als Kontexteigenschaft in der QML-Engine unserer Anwendung registriert.

Das Aussehen der Anwendung wird wie folgt sein

AppCore.h

Das Deklarieren von Signalen und Slots in C++-Code unterscheidet sich nicht wesentlich von klassischem Qt/C++.

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>


class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr);

signals:
    void sendToQml(int count);

public slots:
    void receiveFromQml();

private:
    int m_counter {0};
};

#endif // APPCORE_H

AppCore.cpp

Sowie die Umsetzung der Methoden selbst.

#include "AppCore.h"

AppCore::AppCore(QObject* parent) : QObject(parent)
{
}

void AppCore::receiveFromQml()
{
    // We increase the counter and send a signal with its value
    ++m_counter;
    emit sendToQml(m_counter);
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "AppCore.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    AppCore appCore;    // Create the application core with signals and slots

    QQmlApplicationEngine engine;
    QQmlContext *context = engine.rootContext();

    /* We load the object into the context to establish the connection,
     * and also define the name "appCore" by which the connection will occur
     * */
    context->setContextProperty("appCore", &appCore);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

main.qml

Und jetzt das Interessanteste. Wie man ein in einem QML-Kontext geladenes Objekt verwendet und wie man sich mit seinen Signalen verbindet.

Wie Sie sich erinnern, haben wir das Objekt unter dem Namen appCore in den QML -Kontext geladen, wir werden dieses Objekt verwenden, um darauf zuzugreifen. Aber um eine Verbindung zu einem Signal herzustellen, müssen wir den QML-Typ Connections verwenden.

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Signals and Slots")

    /* Using the Connections Object
     * Establish a connection with the application core object
     * */
    Connections {
        target: appCore // Specify the target to connect
        /* Declare and implement the function as a parameter
         * object and with a name similar to the name of the signal
         * The difference is that we add on at the beginning and then write
         * capitalized
         * */
        onSendToQml: {
            labelCount.text = count // Set the counter to the text label
        }
    }


    Label {
        id: labelCount
        text: "0"

        anchors.bottom: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottomMargin: 15
    }

    Button {
        text: qsTr("Increase counter")
        onClicked: appCore.receiveFromQml() // Вызов слота

        anchors.top: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
    }
}

Auf diese Weise können Sie auf ein Objekt zugreifen, das in den QML-Engine-Kontext geladen wurde, seinen Slot aufrufen und das Signal von diesem Objekt verarbeiten.

In diesem Fall muss auch receiveFromQml() nicht als Slot deklariert werden. Diese Methode kann auch als Q_INVOKABLE -Methode deklariert werden.

public:
    explicit AppCore(QObject *parent = nullptr);
    Q_INVOKABLE void receiveFromQml();

Verwenden von Q_PROPERTY

Die nächste Option ist die Verwendung des Makros Q_PROPERTY. Eine klassische Eigenschaft in Qt für unsere Aufgabe könnte so aussehen

Q_PROPERTY(int counter READ counter WRITE setCounter NOTIFY counterChanged)

Diese Eigenschaft hat die folgenden Komponenten:

  • Eigenschaftstyp sowie sein Name: int Zähler , die an die Variable int m_counter innerhalb der Klasse gebunden sind, dies ist die Codegenerierungslogik in Qt
  • Methodenname lesen, gleich Eigenschaftsname: counter
  • Methodenname zum Setzen des Wertes: setCounter
  • Signal, das Eigenschaftsänderungen anzeigt: counterChanged

Sie können diesem Makro auch zusätzliche Parameter übergeben, aber das würde den Rahmen dieses Artikels sprengen. Und auch die Eigenschaft kann schreibgeschützt sein, also ohne Setter.

Sehen Sie sich nun den vollständigen Code mit Q_PROPERTY an.

AppCore.h

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>


class AppCore : public QObject
{
    Q_OBJECT
public:
    Q_PROPERTY(int counter READ counter WRITE setCounter NOTIFY counterChanged)
    explicit AppCore(QObject *parent = nullptr);

    int counter() const;

public slots:
    void setCounter(int counter);

signals:
    void counterChanged(int counter);

private:
    int m_counter {0};
};

#endif // APPCORE_H

AppCore.cpp

#include "AppCore.h"

AppCore::AppCore(QObject* parent) : QObject(parent)
{

}

int AppCore::counter() const
{
    return m_counter;
}

void AppCore::setCounter(int counter)
{
    if (m_counter == counter)
        return;

    m_counter = counter;
    emit counterChanged(m_counter);
}

main.qml

Hier sehen Sie, dass das Verbinden und Zugreifen auf die Eigenschaft durch den deklarativen Stil des QML-Codes erleichtert wird. Natürlich können Sie nicht immer Eigenschaften verwenden, manchmal müssen Sie nur Signale, Slots und Q_INVOKABLE-Methoden verwenden. Aber für Variablen wie Zähler sind Eigenschaften wahrscheinlich viel bequemer.

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Signals and Slots")

    Label {
        id: labelCount
        text: appCore.counter

        anchors.bottom: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottomMargin: 15
    }

    Button {
        text: qsTr("Increase counter")
        onClicked: ++appCore.counter

        anchors.top: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
    }
}

Verbinden von Signalen innerhalb von QML-Dateien

Betrachten Sie nun die Möglichkeit, Signale und Slots (Funktionen) innerhalb von QML-Dateien zu verbinden. Es wird keinen C++-Code mehr geben.

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    id: mainWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Signals and Slots")

    // Counter property
    property int counter: 0

    // Method for counter manipulation
    function inrementCounter()
    {
        ++counter;
    }

    Label {
        id: labelCount
        text: mainWindow.counter

        anchors.bottom: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottomMargin: 15
    }

    Button {
        id: button
        text: qsTr("Increase counter")

        anchors.top: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter

        Component.onCompleted: {
            // When the button is created, then connect the click signal on the button
            // to the method for increasing the counter in the application window
            button.clicked.connect(mainWindow.inrementCounter)
        }
    }
}

Unter anderem können Sie Signale von Slots verwenden und deaktivieren.

button.clicked.disconnect(mainWindow.inrementCounter)

Signal mit Signal verbinden

Auch in QML ist es noch möglich, ein Signal mit einem Signal zu verbinden, wie in Qt/C++. Betrachten Sie das folgende künstliche Beispiel.

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    id: mainWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Signals and Slots")

    // Announcing a button click signal in the application window
    signal buttonClicked;

    Label {
        id: labelCount
        text: counter

        anchors.bottom: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottomMargin: 15

        // Counter property
        property int counter: 0

        // Method for counter manipulation
        function inrementCounter()
        {
            ++counter;
        }
    }

    Button {
        id: button
        text: qsTr("Increase counter")

        anchors.top: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter

        Component.onCompleted: {
            // When the button is created, then connect the click signal on the button
            // to the method for increasing the counter in the application window
            button.clicked.connect(mainWindow.buttonClicked)
        }
    }

    Component.onCompleted: {
        buttonClicked.connect(labelCount.inrementCounter)
    }
}

In diesem Fall erhöht sich der Zähler weiter, wenn die Taste gedrückt wird. Das Tastendrucksignal ist jedoch nicht direkt mit der Zählerinkrementfunktion verbunden, sondern wird über ein Signal übertragen.

Verwendung von Variablen in Signalen

QML hat auch die Fähigkeit, Variablen in Signalen zu verwenden.

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    id: mainWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Signals and Slots")

    // Signal with argument
    signal setCounter(var number);

    Label {
        id: labelCount
        text: counter

        anchors.bottom: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottomMargin: 15

        // Counter property
        property int counter: 0

        // Method for counter manipulation, takes an argument
        function setCounter(number)
        {
            counter = number;
        }
    }

    Button {
        id: button
        text: qsTr("Increase counter")

        anchors.top: parent.verticalCenter
        anchors.horizontalCenter: parent.horizontalCenter

        onClicked: {
            // We call the signal of the application window for installing the counter indicating the new counter value
            mainWindow.setCounter(labelCount.counter + 1)
        }
    }

    Component.onCompleted: {
        setCounter.connect(labelCount.setCounter)
    }
}

Fazit

Zum größten Teil passt dieser gesamte Artikel in ein paar Punkte:

  • In C++ können Sie Signale, Slots und Q_INVOKABLE-Methoden verwenden und Eigenschaften mit dem Q_PROPERTY-Makro erstellen, um mit der QML-Schicht zu interagieren
  • Um auf Signale von Objekten zu reagieren, können Sie den Typ QML-Verbindungen verwenden
  • Q_PROPERTY folgt dem deklarativen QML-Stil und kann automatisch neue Werte setzen, wenn eine Eigenschaft geändert wird, wenn die Eigenschaft zu einem beliebigen Objekt in QML hinzugefügt wurde. In diesem Fall werden Signal-Slot-Verbindungen automatisch hergestellt.
  • In QML können Sie Signal-/Slot-Verbindungen mit der folgenden Syntax aktivieren und deaktivieren:
  • object1.signal.connect (object2.slot)
  • object1.signal.disconnect (object2.slot)
  • Signale in QML können auch mit anderen Signalen verbunden werden, wie es in Qt/C++ gemacht wird
  • Signale in QML können auch Argumente haben
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken