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 хостинг.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

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

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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