Показаны различия между двумя версиями страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
develop:qt:quick3 [2021/08/29 14:08] admin |
develop:qt:quick3 [2021/09/04 10:55] (текущий) admin |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ====== Qt Quick: Модель/ | + | ====== Qt Quick: Модель/ |
- | ===== ===== | + | ===== Модель/ |
- | ==== ==== | + | В **QML** предоставляет механизм отделения данных от их представления. За показ отвечают элементы представления и делегаты, |
+ | |||
+ | ==== Модели ==== | ||
+ | **Модель** - предоставляет интерфейс для обращения к данным, | ||
+ | |||
+ | === Модель списка === | ||
+ | Представлена элементом **ListModel** и содержит последовательность элементов: | ||
+ | **ListElement** содержит свойства данных, | ||
+ | Элементы можно описывать как вручную, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <code QML> | ||
+ | import QtQuick 2.8 | ||
+ | |||
+ | ListModel | ||
+ | { | ||
+ | ListElement | ||
+ | { | ||
+ | artist: " | ||
+ | album: " | ||
+ | year: 2011 | ||
+ | cover: " | ||
+ | } | ||
+ | ListElement | ||
+ | { | ||
+ | artist: "Dark Princess" | ||
+ | album: " | ||
+ | year: 2005 | ||
+ | cover: " | ||
+ | } | ||
+ | ListElement | ||
+ | { | ||
+ | artist: " | ||
+ | album: "The Unfo" | ||
+ | year: 2011 | ||
+ | cover: " | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === XML-модель === | ||
+ | **XmlListModel**- тоже модель списка и используется для XML-данных. Задействует для заполнения данными опросы **XPath** и присваивает данные свойствам.\\ | ||
+ | Для каждого определяемого свойства, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <code XML> | ||
+ | <?xml version = " | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.XmlListModel 2.0 | ||
+ | |||
+ | XmlListModel | ||
+ | { | ||
+ | source: " | ||
+ | query: "/ | ||
+ | XmlRole { name: " | ||
+ | XmlRole { name: " | ||
+ | XmlRole { name: " | ||
+ | XmlRole { name: " | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === JSON-модель === | ||
+ | ---- | ||
+ | Благодаря поддержке **JavaScript**, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <code QML> | ||
+ | import QtQuick 2.8; | ||
+ | |||
+ | var jsonModel = [ | ||
+ | { | ||
+ | artist: " | ||
+ | album: " | ||
+ | year: 2011, | ||
+ | cover: " | ||
+ | }, | ||
+ | { | ||
+ | artist: "Dark Princess", | ||
+ | album: " | ||
+ | year: 2005, | ||
+ | cover: " | ||
+ | } | ||
+ | , | ||
+ | { | ||
+ | artist: " | ||
+ | album: "The Unfo", | ||
+ | year: 2011, | ||
+ | cover: " | ||
+ | } | ||
+ | ] | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Представление данных ==== | ||
+ | === ListView | ||
---- | ---- | ||
+ | Отвечает за отображение данных модели в виде столбца или строки.\\ | ||
+ | За отображение каждого элемента списка в отдельности отвечает **делегат**.\\ | ||
+ | В примере, | ||
+ | Далее определяем собсна саму модель **ListView**, | ||
< | < | ||
- | < | + | < |
<code QML> | <code QML> | ||
+ | import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0 | ||
+ | import " | ||
+ | ApplicationWindow | ||
+ | { | ||
+ | width: 200; height: 360; visible: true | ||
+ | Rectangle | ||
+ | { | ||
+ | id: mainrect | ||
+ | anchors.fill: | ||
+ | color: " | ||
+ | Component | ||
+ | { | ||
+ | id: delegate | ||
+ | Item | ||
+ | { | ||
+ | width: mainrect.width; | ||
+ | Row | ||
+ | { | ||
+ | anchors.verticalCenter: | ||
+ | Image | ||
+ | { | ||
+ | width: 64; height: 64 | ||
+ | source: modelData.cover | ||
+ | smooth: true | ||
+ | } | ||
+ | Column | ||
+ | { | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | text: modelData.artist | ||
+ | font.pointSize: | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | text: modelData.album | ||
+ | font.pointSize: | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | text: modelData.year | ||
+ | font.pointSize: | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | ListView | ||
+ | { | ||
+ | focus: true | ||
+ | header: Rectangle | ||
+ | { | ||
+ | width: parent.width; | ||
+ | gradient: Gradient | ||
+ | { | ||
+ | GradientStop { position: 0; color: " | ||
+ | GradientStop { position: 0.7; color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | color: " | ||
+ | font.bold: true; font.pointSize: | ||
+ | } | ||
+ | } | ||
+ | footer: Rectangle | ||
+ | { | ||
+ | width: parent.width; | ||
+ | gradient: Gradient | ||
+ | { | ||
+ | GradientStop { position: 0; color: " | ||
+ | GradientStop { position: 0.7; color: " | ||
+ | } | ||
+ | } | ||
+ | highlight: Rectangle | ||
+ | { | ||
+ | width: parent.width | ||
+ | color: " | ||
+ | } | ||
+ | anchors.fill: | ||
+ | model: CDs.jsonModel | ||
+ | delegate: delegate | ||
+ | } | ||
+ | } | ||
+ | } | ||
</ | </ | ||
</ | </ | ||
+ | |||
+ | === GridView === | ||
+ | ---- | ||
+ | **GridView** автоматически заполняет всю область элементами в табличном порядке, | ||
+ | Использование почти полностью идентично предыдущему примеру, | ||
+ | < | ||
+ | < | ||
+ | <code QML> | ||
+ | import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0 | ||
+ | import " | ||
+ | ApplicationWindow | ||
+ | { | ||
+ | width: 380; height: 420; visible: true | ||
+ | Rectangle | ||
+ | { | ||
+ | id: mainrect | ||
+ | anchors.fill: | ||
+ | color: " | ||
+ | Component | ||
+ | { | ||
+ | id: delegate | ||
+ | Item | ||
+ | { | ||
+ | width: 120; height: 120 | ||
+ | Column | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | Image | ||
+ | { | ||
+ | anchors.horizontalCenter: | ||
+ | width: 64; height: 64 | ||
+ | source: modelData.cover | ||
+ | smooth: true | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | GridView | ||
+ | { | ||
+ | cellWidth: 120; cellHeight: 120 | ||
+ | focus: true | ||
+ | header: Rectangle | ||
+ | { | ||
+ | width: parent.width; | ||
+ | gradient: Gradient | ||
+ | { | ||
+ | GradientStop { position: 0; color: " | ||
+ | GradientStop { position: 0.7; color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | color: " | ||
+ | font.bold: true; font.pointSize: | ||
+ | } | ||
+ | } | ||
+ | footer: Rectangle | ||
+ | { | ||
+ | width: parent.width; | ||
+ | gradient: Gradient | ||
+ | { | ||
+ | GradientStop { position: 0; color: " | ||
+ | GradientStop { position: 0.7; color: " | ||
+ | } | ||
+ | } | ||
+ | highlight: Rectangle | ||
+ | { | ||
+ | width: parent.width | ||
+ | color: " | ||
+ | } | ||
+ | anchors.fill: | ||
+ | model: CDs.jsonModel | ||
+ | delegate: delegate | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
- | ==== ==== | + | |
+ | === PathView | ||
---- | ---- | ||
+ | Показывает элементы в виде замкнутой линии.\\ | ||
+ | Делегат идентичен предыдущим. ключевой момент в создании элемента **Path**, этот элемент задает форму замкнутой линии, он присваивается свойству **path** элемента **PathView**, | ||
< | < | ||
- | < | + | < |
<code QML> | <code QML> | ||
+ | import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0 | ||
+ | import " | ||
+ | ApplicationWindow | ||
+ | { | ||
+ | width: 450; height: 170; visible: true | ||
+ | Rectangle | ||
+ | { | ||
+ | anchors.fill: | ||
+ | color: " | ||
+ | Component | ||
+ | { | ||
+ | id: delegate | ||
+ | Item | ||
+ | { | ||
+ | width: item.width; height: item.height | ||
+ | Column | ||
+ | { | ||
+ | id: item | ||
+ | Image | ||
+ | { | ||
+ | width: 90; height: 90 | ||
+ | source: modelData.cover | ||
+ | smooth: true | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | color: " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | Path | ||
+ | { | ||
+ | id: itemsPath | ||
+ | startX: 45; startY: 80 // Не совсем понятны эти значения | ||
+ | PathLine {x: 500; y: 80} // И эти тоже | ||
+ | } | ||
+ | PathView | ||
+ | { | ||
+ | id: itemsView | ||
+ | focus: true | ||
+ | anchors.fill: | ||
+ | model: CDs.jsonModel | ||
+ | delegate: delegate | ||
+ | path: itemsPath | ||
+ | pathItemCount: | ||
+ | } | ||
+ | } | ||
+ | } | ||
</ | </ | ||
</ | </ | ||
+ | Пример прикольной компоновки для предыдущего примера, | ||
+ | < | ||
+ | < | ||
+ | <code QML> | ||
+ | Path | ||
+ | { | ||
+ | id: itemsPath | ||
+ | startX: 150; startY: 150 | ||
+ | PathAttribute { name: " | ||
+ | PathAttribute { name: " | ||
+ | PathQuad { x: 150; y: 25; controlX: 460; controlY: 75 } | ||
+ | PathAttribute { name: " | ||
+ | PathAttribute { name: " | ||
+ | PathQuad { x: 150; y: 150; controlX: -80; controlY: 75 } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== Визуальная модель данных ==== | ||
+ | ---- | ||
+ | **VisualItemModel** - модель которая не нуждается в делегате и сама отвечает за представление своих данных, | ||
+ | < | ||
+ | < | ||
+ | <code QML> | ||
+ | // Отдельный файл с данными | ||
+ | import QtQuick 2.12 | ||
+ | |||
+ | VisualItemModel | ||
+ | { | ||
+ | Row | ||
+ | { | ||
+ | Image | ||
+ | { | ||
+ | width: 64; height: 64 | ||
+ | source: " | ||
+ | smooth: true | ||
+ | } | ||
+ | Column | ||
+ | { | ||
+ | Text { color: " | ||
+ | Text { color: " | ||
+ | Text { color: " | ||
+ | } | ||
+ | } | ||
+ | Rectangle | ||
+ | { | ||
+ | width: parent.width; | ||
+ | color: " | ||
+ | Text | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | color: " | ||
+ | text: " | ||
+ | } | ||
+ | } | ||
+ | Row | ||
+ | { | ||
+ | Image | ||
+ | { | ||
+ | width: 64; height: 64 | ||
+ | source: " | ||
+ | smooth: true | ||
+ | } | ||
+ | Column | ||
+ | { | ||
+ | Text { color: " | ||
+ | Text { color: " | ||
+ | Text { color: " | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | // Основной файл программы | ||
+ | import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0 | ||
+ | import " | ||
+ | |||
+ | ApplicationWindow | ||
+ | { | ||
+ | width: 250; height: 250; visible: true | ||
+ | Rectangle | ||
+ | { | ||
+ | anchors.fill: | ||
+ | color: " | ||
+ | Flickable | ||
+ | { | ||
+ | id: view | ||
+ | width: 250; height: 500 | ||
+ | contentWidth: | ||
+ | anchors.fill: | ||
+ | Column | ||
+ | { | ||
+ | id: column | ||
+ | anchors.fill: | ||
+ | spacing: 5 | ||
+ | Repeater | ||
+ | { | ||
+ | model: CDs{} | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
- | ==== ==== | + | |
+ | ===== Qt Quick и C++ ===== | ||
+ | ==== Использование языка QML в C++ ==== | ||
---- | ---- | ||
+ | В QML интегрирован класс **QQuickWidget**, | ||
+ | Расположен он в модуле **quickwidgets**, | ||
+ | < | ||
+ | < | ||
+ | |||
+ | **pro-файл** содержит: | ||
+ | |||
+ | Файл **" | ||
+ | <code cpp-qt> | ||
+ | #ifndef MYWIDGET_H | ||
+ | #define MYWIDGET_H | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | class MyWidget : public QWidget | ||
+ | { | ||
+ | Q_OBJECT | ||
+ | |||
+ | public: | ||
+ | MyWidget(QWidget *parent = nullptr); | ||
+ | ~MyWidget(); | ||
+ | }; | ||
+ | #endif // MYWIDGET_H | ||
+ | </ | ||
+ | |||
+ | |||
+ | Файл **" | ||
+ | <code cpp-qt> | ||
+ | #include " | ||
+ | |||
+ | MyWidget:: | ||
+ | { | ||
+ | QQuickWidget* pv= new QQuickWidget(QUrl(" | ||
+ | QVBoxLayout* pvbox= new QVBoxLayout; | ||
+ | pvbox-> | ||
+ | setLayout(pvbox); | ||
+ | } | ||
+ | |||
+ | MyWidget:: | ||
+ | { | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | Файл элемента QML, **main.qml**, | ||
+ | <code QML> | ||
+ | import QtQuick 2.0 | ||
+ | |||
+ | Rectangle | ||
+ | { | ||
+ | color: " | ||
+ | width: 100; height: 100 | ||
+ | Text | ||
+ | { | ||
+ | objectName: " | ||
+ | anchors.centerIn: | ||
+ | text: "Hello QML" | ||
+ | | ||
+ | function setFontSize(newSize) | ||
+ | { | ||
+ | font.pixelSize= newSize | ||
+ | return font.family + " Size= "+ newSize | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Взаимодействие из C++ со св-вами элементов QML === | ||
+ | ---- | ||
+ | Базовый QML элемент **Item** реализован в C++ классом **QQuickItem**, | ||
+ | Через свойство **objectName**, | ||
+ | |||
+ | В следующем примере (на базе предыдущего), | ||
+ | Далее у этого объекта, | ||
+ | С помощью метода **findChild()** мы можем получить указатели на дочерние элементы, | ||
+ | |||
+ | Затем вызываем пользовательскую JavaScript функцию из **QML**:\\ | ||
+ | Все функции в QML представлены в метаобъектной информации, | ||
+ | В этот метод мы передаем указатель на объект, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | На основании предыдущего примера, | ||
+ | <code cpp-qt> | ||
+ | MyWidget:: | ||
+ | { | ||
+ | QQuickWidget* pv= new QQuickWidget(QUrl(" | ||
+ | QVBoxLayout* pvbox= new QVBoxLayout; | ||
+ | pvbox-> | ||
+ | setLayout(pvbox); | ||
+ | |||
+ | QQuickItem *pqiRoot= pv-> | ||
+ | if(pqiRoot) | ||
+ | { | ||
+ | pqiRoot-> | ||
+ | QObject *pObjText= pqiRoot-> | ||
+ | if(pObjText) | ||
+ | { | ||
+ | pObjText-> | ||
+ | pObjText-> | ||
+ | QVariant varRet; | ||
+ | QMetaObject:: | ||
+ | qDebug() << varRet; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Соединение QML-сигналов со слотами C++ === | ||
+ | ---- | ||
+ | В прошлых примерах мы использовали QML внутри виджетов, | ||
+ | На этот раз вся **форма** будет **QML**, на **C++** реализованы **действия** по нажатию кнопок.\\ | ||
+ | В проект добавлены только 2 модуля: | ||
< | < | ||
- | < | + | < |
+ | **Форма приложения** | ||
<code QML> | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.Controls 2.2; import QtQuick.Window 2.2 | ||
+ | ApplicationWindow | ||
+ | { | ||
+ | visible: true | ||
+ | width: 150; height: 150; | ||
+ | Column | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | spacing: 5 | ||
+ | Button | ||
+ | { | ||
+ | signal infoClick(string str) | ||
+ | objectName: " | ||
+ | text: " | ||
+ | onClicked: infoClick(" | ||
+ | } | ||
+ | Button | ||
+ | { | ||
+ | signal quitClick() | ||
+ | objectName: " | ||
+ | text: " | ||
+ | onClicked: quitClick() | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Класс со слотами** | ||
+ | <code cpp-qt> | ||
+ | #ifndef MYWIDGET_H | ||
+ | #define MYWIDGET_H | ||
+ | |||
+ | #include < | ||
+ | |||
+ | class CppConnect : public QObject | ||
+ | { | ||
+ | Q_OBJECT | ||
+ | |||
+ | public: | ||
+ | CppConnect(QObject *parent = nullptr) | ||
+ | { | ||
+ | } | ||
+ | |||
+ | public slots: | ||
+ | void slotQuit() | ||
+ | { | ||
+ | qApp-> | ||
+ | } | ||
+ | |||
+ | void slotInfo(const QString str) | ||
+ | { | ||
+ | qDebug() << str; | ||
+ | } | ||
+ | |||
+ | }; | ||
+ | #endif // MYWIDGET_H | ||
+ | </ | ||
+ | |||
+ | **Соединение сигналов со слотами, | ||
+ | <code cpp-qt> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | QGuiApplication app(argc, argv); | ||
+ | QQmlApplicationEngine eng; | ||
+ | QQmlComponent comp(& | ||
+ | CppConnect cc; | ||
+ | QObject *pobj= comp.create(); | ||
+ | |||
+ | QObject *pcmdQuitButton= pobj-> | ||
+ | if(pcmdQuitButton) | ||
+ | { | ||
+ | QObject:: | ||
+ | } | ||
+ | |||
+ | QObject *pcmdInfoButton= pobj-> | ||
+ | if(pcmdInfoButton) | ||
+ | { | ||
+ | QObject:: | ||
+ | } | ||
+ | return app.exec(); | ||
+ | } | ||
</ | </ | ||
</ | </ | ||
+ | |||
+ | ==== Использование компонентов C++ в QML ==== | ||
+ | ---- | ||
+ | В QML реализована возможность расширения при помощи C++, благодаря этому можно QML расширять новыми элементами из C++.\\ | ||
+ | Существующие технологии импортируются директивой **import**, например " | ||
+ | |||
+ | Работа происходит через класс контекста **QQmlContext**, | ||
+ | Используя этот указатель вы можете ввести в дерево контекста новые объекты классов, | ||
+ | После этого, свойства класса **QObject** станут свойствами QML, а слоты и методы (декларированные с Q_INVOKABLE) смогут вызываться из вашего QML-элемента.\\ | ||
+ | Класс **QQuickWidget** так же содержит объект класса **QQmlEngine** (вызов engine()), который предоставляет среду для исполнения QML.\\ | ||
+ | |||
+ | |||
+ | === Экспорт объектов и виджетов из C++ в QML === | ||
+ | ---- | ||
+ | Пример экспорта, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | **Файл класса myWidget.cpp** | ||
+ | <code cpp-qt> | ||
+ | #include " | ||
+ | |||
+ | MyWidget:: | ||
+ | { | ||
+ | QQuickWidget *pv= new QQuickWidget(this); | ||
+ | pv-> | ||
+ | |||
+ | QVBoxLayout *pvbx= new QVBoxLayout(this); | ||
+ | pvbx-> | ||
+ | setLayout(pvbx); | ||
+ | |||
+ | QQmlContext *pcon= pv-> | ||
+ | QStringList lst; | ||
+ | for(int i= 0; i < 100; i++) | ||
+ | lst << " | ||
+ | QStringListModel *pmodel= new QStringListModel(this); | ||
+ | pmodel-> | ||
+ | |||
+ | pcon-> | ||
+ | pcon-> | ||
+ | pcon-> | ||
+ | pcon-> | ||
+ | } | ||
+ | |||
+ | void MyWidget:: | ||
+ | { | ||
+ | QMessageBox:: | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **Форма QML** | ||
+ | <code QML> | ||
+ | import QtQuick 2.8 | ||
+ | |||
+ | Rectangle | ||
+ | { | ||
+ | width: 200; height: 200; | ||
+ | color: myColor | ||
+ | Text | ||
+ | { | ||
+ | anchors.centerIn: | ||
+ | text: myText | ||
+ | } | ||
+ | ListView | ||
+ | { | ||
+ | anchors.fill: | ||
+ | model: myModel | ||
+ | delegate: Text { text: model.display } | ||
+ | } | ||
+ | MouseArea | ||
+ | { | ||
+ | anchors.fill: | ||
+ | onPressed: | ||
+ | { | ||
+ | myWidget.setWindowTitle(" | ||
+ | myWidget.slotDisplayDialog(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Использование зарегистр объектов C++ в QML === | ||
+ | ---- | ||
+ | Как я понял, это передача в QML только **конкретных свойств и методов**, | ||
+ | Прежде всего производим регистрацию нашего класса, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | **Calculate.h** | ||
+ | <code cpp-qt> | ||
+ | #ifndef CALCULATION_H | ||
+ | #define CALCULATION_H | ||
+ | |||
+ | #include < | ||
+ | |||
+ | class Calculation : public QObject | ||
+ | { | ||
+ | Q_OBJECT | ||
+ | private: | ||
+ | Q_PROPERTY(qulonglong input WRITE setInputValue | ||
+ | READ inputValue | ||
+ | NOTIFY inputValueChanged) // Уведомление об изменении | ||
+ | Q_PROPERTY(qulonglong result READ resultValue | ||
+ | | ||
+ | qulonglong m_nInput; | ||
+ | qulonglong m_nResult; | ||
+ | |||
+ | public: | ||
+ | explicit Calculation(QObject *parent = nullptr); | ||
+ | |||
+ | Q_INVOKABLE qulonglong factorial(const qulonglong &n); | ||
+ | qulonglong inputValue() const; | ||
+ | void setInputValue(const qulonglong& | ||
+ | qulonglong resultValue() const; | ||
+ | |||
+ | signals: | ||
+ | void inputValueChanged(qulonglong); | ||
+ | void resultValueChanged(qulonglong); | ||
+ | }; | ||
+ | |||
+ | #endif // CALCULATION_H | ||
+ | </ | ||
+ | |||
+ | |||
+ | **Calculate.cpp** | ||
+ | <code cpp-qt> | ||
+ | #include " | ||
+ | |||
+ | Calculation:: | ||
+ | { | ||
+ | } | ||
+ | |||
+ | qulonglong Calculation:: | ||
+ | { | ||
+ | return n ? (n * factorial(n-1)) : 1; | ||
+ | } | ||
+ | |||
+ | qulonglong Calculation:: | ||
+ | { | ||
+ | return m_nInput; | ||
+ | } | ||
+ | |||
+ | qulonglong Calculation:: | ||
+ | { | ||
+ | return m_nResult; | ||
+ | } | ||
+ | |||
+ | void Calculation:: | ||
+ | { | ||
+ | m_nInput= n; | ||
+ | m_nResult= factorial(m_nInput); | ||
+ | emit inputValueChanged(m_nInput); | ||
+ | emit resultValueChanged(m_nResult); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **main.cpp** | ||
+ | <code cpp-qt> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | QGuiApplication app(argc, argv); | ||
+ | qmlRegisterType< | ||
+ | QQmlApplicationEngine engine; | ||
+ | engine.load(QUrl(" | ||
+ | |||
+ | return app.exec(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **Два варианта** реализации, | ||
+ | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.3; | ||
+ | import my.class.Calc 1.0 | ||
+ | |||
+ | ApplicationWindow | ||
+ | { | ||
+ | title: " | ||
+ | visible: true | ||
+ | Calculation | ||
+ | { | ||
+ | id: calc | ||
+ | } | ||
+ | ColumnLayout | ||
+ | { | ||
+ | anchors.fill: | ||
+ | RowLayout // Первый подход, | ||
+ | { | ||
+ | SpinBox | ||
+ | { | ||
+ | id: sbx | ||
+ | value: 0 | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | text: " | ||
+ | } | ||
+ | } | ||
+ | RowLayout // Второй подход, | ||
+ | { | ||
+ | SpinBox | ||
+ | { | ||
+ | value: 0 | ||
+ | onValueChanged: | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | text: " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **Альтернативный подход** с использованием сигналов | ||
+ | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.3; | ||
+ | import my.class.Calc 1.0 | ||
+ | |||
+ | ApplicationWindow | ||
+ | { | ||
+ | title: " | ||
+ | visible: true | ||
+ | Calculatoin | ||
+ | { | ||
+ | input: sbx.value | ||
+ | onResultValueChanged: | ||
+ | } | ||
+ | RowLayout | ||
+ | { | ||
+ | SpinBox | ||
+ | { | ||
+ | id: sbx | ||
+ | value: 0 | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | id: txt | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Реализация визуальных элементов QML на C++ === | ||
+ | ---- | ||
+ | Все базовые **элементы QML** (такие как Rectangle или Text), **реализованы на C++** (QQuickRectangle, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | **Ellipse.h** | ||
+ | <code cpp-qt> | ||
+ | #ifndef ELLIPSE_H | ||
+ | #define ELLIPSE_H | ||
+ | |||
+ | #include < | ||
+ | |||
+ | class QPainter; | ||
+ | |||
+ | class Ellipse: public QQuickPaintedItem | ||
+ | { | ||
+ | Q_OBJECT | ||
+ | |||
+ | private: | ||
+ | Q_PROPERTY(QColor color WRITE setColorValue | ||
+ | READ colorValue) | ||
+ | QColor m_color; | ||
+ | |||
+ | public: | ||
+ | Ellipse(QQuickItem *parent= nullptr); | ||
+ | // Отвечает рисование элемента, | ||
+ | void paint(QPainter *ppainter); | ||
+ | QColor colorValue() const; | ||
+ | void setColorValue(const QColor& | ||
+ | }; | ||
+ | |||
+ | #endif // ELLIPSE_H | ||
+ | </ | ||
+ | |||
+ | |||
+ | **Ellipse.hpp** | ||
+ | <code cpp-qt> | ||
+ | #include " | ||
+ | #include < | ||
+ | |||
+ | Ellipse:: | ||
+ | { | ||
+ | } | ||
+ | |||
+ | void Ellipse:: | ||
+ | { | ||
+ | ppainter-> | ||
+ | ppainter-> | ||
+ | ppainter-> | ||
+ | ppainter-> | ||
+ | } | ||
+ | |||
+ | QColor Ellipse:: | ||
+ | { | ||
+ | return this-> | ||
+ | } | ||
+ | |||
+ | void Ellipse:: | ||
+ | { | ||
+ | this-> | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **main.hpp** | ||
+ | <code cpp-qt> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | QGuiApplication app(argc, argv); | ||
+ | qmlRegisterType< | ||
+ | QQmlApplicationEngine engine; | ||
+ | engine.load(QUrl(" | ||
+ | |||
+ | return app.exec(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **main.qml** | ||
+ | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.Controls 2.2 | ||
+ | import my.class.Ellipse 1.0 | ||
+ | |||
+ | ApplicationWindow | ||
+ | { | ||
+ | title: "Paint Element"; | ||
+ | visible: true | ||
+ | Ellipse | ||
+ | { | ||
+ | anchors.fill: | ||
+ | color: " | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Класс QQuickImageProvider ==== | ||
+ | ---- | ||
+ | Этот класс является неким объектом, | ||
+ | Т.к. ImageProvider возвращает (методом request) изображение в как таковом виде (тип данных image/ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | |||
+ | **ImageProvider.h** | ||
+ | <code cpp-qt> | ||
+ | #ifndef IMAGEPROVIDER_H | ||
+ | #define IMAGEPROVIDER_H | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | class ImageProvider: | ||
+ | { | ||
+ | private: | ||
+ | QImage brightness(const QImage & | ||
+ | |||
+ | public: | ||
+ | ImageProvider(); | ||
+ | QImage requestImage(const QString&, | ||
+ | }; | ||
+ | |||
+ | #endif // IMAGEPROVIDER_H | ||
+ | </ | ||
+ | |||
+ | |||
+ | **ImageProvider.hpp** | ||
+ | <code cpp-qt> | ||
+ | #include " | ||
+ | |||
+ | ImageProvider:: | ||
+ | { | ||
+ | } | ||
+ | |||
+ | QImage ImageProvider:: | ||
+ | { | ||
+ | QImage imgTemp= imgOrig; | ||
+ | qint32 nHeigt= imgTemp.height(); | ||
+ | qint32 nWidth= imgTemp.width(); | ||
+ | |||
+ | for(qint32 y= 0; y < nHeigt; ++y) | ||
+ | { | ||
+ | QRgb *tempLine= reinterpret_cast< | ||
+ | for(qint32 x= 0; x < nWidth; ++x) | ||
+ | { | ||
+ | int r= qRed(*tempLine) + n; | ||
+ | int g= qGreen(*tempLine) + n; | ||
+ | int b= qBlue(*tempLine) + n; | ||
+ | int a= qAlpha(*tempLine); | ||
+ | |||
+ | *tempLine++ = qRgba(r > 255 ? 255 : r < 0 ? 0:r, | ||
+ | g > 255 ? 255 : g < 0 ? 0:g, | ||
+ | b > 255 ? 255 : b < 0 ? 0:b, | ||
+ | a); | ||
+ | } | ||
+ | } | ||
+ | return imgTemp; | ||
+ | } | ||
+ | |||
+ | QImage ImageProvider:: | ||
+ | { | ||
+ | QStringList lst= strId.split(";" | ||
+ | bool bOk= false; | ||
+ | int nBrightness= lst.last().toInt(& | ||
+ | QImage img= brightness(QImage(":/" | ||
+ | |||
+ | if(ps) | ||
+ | *ps= img.size(); | ||
+ | |||
+ | return img; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **main.hpp** | ||
+ | <code cpp-qt> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | QGuiApplication app(argc, argv); | ||
+ | QQmlApplicationEngine engine; | ||
+ | engine.addImageProvider(QLatin1String(" | ||
+ | engine.load(QUrl(" | ||
+ | |||
+ | return app.exec(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | **main.qml** | ||
+ | <code QML> | ||
+ | import QtQuick 2.8; import QtQuick.Controls 2.2 | ||
+ | |||
+ | ApplicationWindow | ||
+ | { | ||
+ | title: " | ||
+ | visible: true | ||
+ | Column | ||
+ | { | ||
+ | id: controls | ||
+ | Image | ||
+ | { | ||
+ | id: img | ||
+ | source: " | ||
+ | } | ||
+ | Slider | ||
+ | { | ||
+ | id: sld | ||
+ | width: img.width | ||
+ | value: 0.75 | ||
+ | stepSize: 0.01 | ||
+ | property int brightnessValue: | ||
+ | } | ||
+ | Text | ||
+ | { | ||
+ | width: img.width | ||
+ | text: "< | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ |