Evgenii Legotckoi
Evgenii LegotckoiҚар. 4, 2019, 5:15 Т.Ж.

QML - Сабақ 036. QML-де сигналдармен және слоттармен жұмыс

Бұл мақала осы сайттағы барлық алдыңғы мақалалармен салыстырғанда QML жүйесіндегі сигналдар мен слоттардың ең толық сипаттамасы болып табылады.

Бұл мақалада мен Qt/QML + Qt/C++ бағдарламаларымен жұмыс істегенде төмендегілерді түсіндіруге тырысамын:

  • QML деңгейінде тіркелетін C++ класындағы әдістер деп те аталатын сигналдар мен слоттарды жариялау тәсілдері
  • контекст ретінде C++-де жарияланған кластардың сигналдарына қосылу жолдары
  • Q_PROPERTY-мен жұмыс істеу, ол да сигналдар мен слоттарды қажет етеді
  • QML-де сигналдар мен слоттарды қосу тәсілдері
  • және т.б.

C++ сыныбының сигналдары мен слоттары

QML-де сигналдармен және слоттармен жұмыс істейтін бірінші классты жасайық. Бұл мен көрсеткен алғашқы мысалдардың бірі, бірақ мақала мүмкіндігінше толық болуы үшін осы мысалды қайталаймын.

Бұл мысалда мен бір түймесі бар қолданбаны жасағым келеді және сол түймені басу C++ сыныбының ішіндегі есептегішті арттырады. Бұл C++ сыныбы қолданбамыздың QML жүйесінде мәтінмәндік сипат ретінде тіркеледі.

Қолданбаның сыртқы түрі келесідей болады

AppCore.h

Сигналдарды және слоттарды C++ кодында жариялау классикалық 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

Сондай-ақ әдістердің өзін жүзеге асыру.

#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

Ал енді ең қызығы. QML контекстінде жүктелген нысанды қалай пайдалану керек және оның сигналдарына қосылу жолы.

Естеріңізде болса, біз нысанды QML контекстіне appCore атауымен жүктеген болатынбыз, оған қол жеткізу үшін осы нысанды қолданамыз. Бірақ сигналға қосылу үшін QML Connections түрін пайдалануымыз керек.

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

Осылайша QML механизмінің контекстіне жүктелген нысанға қол жеткізуге, оның ұясына қоңырау шалуға және сол нысаннан сигналды өңдеуге болады.

Бұл жағдайда receiveFromQml() ұяшығы ретінде жариялаудың да қажеті жоқ. Бұл әдісті Q_INVOKABLE әдісі ретінде де жариялауға болады.

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

Q_PROPERTY пайдалану

Келесі опция Q_PROPERTY макросын пайдалану болып табылады. Біздің тапсырмамыз үшін Qt классикалық сипат келесідей болуы мүмкін

Q_PROPERTY(int counter READ counter WRITE setCounter NOTIFY counterChanged)

Бұл сипат келесі компоненттерден тұрады:

  • сипат түрі, сонымен қатар оның атауы: int m_counter айнымалысына класс ішіндегі байланыстырылған int counter , бұл Qt ішіндегі кодты генерациялау логикасы.
  • оқу әдісі атауы, сипат атымен бірдей: санауыш
  • мәнді орнату әдісінің атауы: setCounter
  • сипаттың өзгеруін көрсететін сигнал: counterChanged

Сондай-ақ, осы макросқа қосымша параметрлерді беруге болады, бірақ бұл мақаланың ауқымынан тыс. Сондай-ақ сипат тек оқу үшін, яғни орнатушысыз болуы мүмкін.

Енді Q_PROPERTY арқылы толық кодты қараңыз.

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

Мұнда сіз сипатты қосу және оған қол жеткізу QML кодының декларативті стилі арқылы жеңілдетілгенін көресіз. Әрине, сіз әрқашан сипаттарды пайдалана алмайсыз, кейде сізге сигналдарды, ұяшықтарды және Q_INVOKABLE әдістерін пайдалану қажет. Бірақ санауыш сияқты айнымалылар үшін сипаттар әлдеқайда ыңғайлы болуы мүмкін.

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

QML файлдарының ішіндегі сигналдарды қосу

Енді QML файлдарының ішіндегі сигналдар мен слоттарды (функцияларды) қосу опциясын қарастырыңыз. Енді C++ коды болмайды.

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

Басқа нәрселермен қатар, ұялардағы сигналдарды пайдалануға және өшіруге болады.

button.clicked.disconnect(mainWindow.inrementCounter)

Сигналды сигналға қосыңыз

Сондай-ақ QML-де Qt / C ++ сияқты сигналды сигналға қосуға болады. Келесі жасанды мысалды қараңыз.

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

Бұл жағдайда түйме басылғанда есептегіш көбейе береді. Бірақ түймені басу сигналы есептегіш өсу функциясына тікелей қосылмайды, бірақ сигнал арқылы беріледі.

Сигналдарда айнымалы мәндерді пайдалану

QML сонымен қатар сигналдарда айнымалы мәндерді пайдалану мүмкіндігіне ие.

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

Қорытынды

Көбінесе бұл мақала бірнеше тармақтарға сәйкес келеді:

  • C++ тілінде QML деңгейімен әрекеттесу үшін Q_PROPERTY макросын пайдаланып сигналдарды, ұяшықтарды, Q_INVOKABLE әдістерін пайдалануға және сипаттарды жасауға болады.
  • Нысандардан келетін сигналдарға жауап беру үшін QML қосылымдары түрін пайдалануға болады
  • Q_PROPERTY QML декларативті стилін ұстанады және егер сипат QML ішіндегі кез келген нысанға қосылған болса, сипат өзгерген кезде жаңа мәндерді автоматты түрде орната алады. Бұл жағдайда сигнал ұясының қосылымдары автоматты түрде орнатылады.
  • QML жүйесінде келесі синтаксисті пайдаланып сигнал/слот қосылымдарын қосуға және өшіруге болады:
  • object1.signal.connect (object2.slot)
  • object1.сигнал.ажырату (объект2.слот)
  • QML-дегі сигналдар Qt/C++ тілінде орындалғандай, басқа сигналдарға да қосылуы мүмкін
  • QML-дегі сигналдарда да дәлелдер болуы мүмкін
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз