Бұл мақала осы сайттағы барлық алдыңғы мақалалармен салыстырғанда 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-дегі сигналдарда да дәлелдер болуы мүмкін