Инструменты пользователя

Инструменты сайта


develop:qt:quick3

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
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{...} ...**.\\ 
 +**ListElement** содержит свойства данных, все они **определяются пользователем**, стандартных нет.\\ 
 +Элементы можно описывать как вручную, так и динамически, поддерживаются функции типа: **append()**, **insert()**, **remove()**, **move** и т.д.\\  
 + 
 +<details> 
 +<summary>:!: Пример: Статическое описание содержимого модели</summary> 
 +<code QML> 
 +import QtQuick 2.8 
 + 
 +ListModel 
 +
 +    ListElement 
 +    { 
 +        artist: "Amaranthe" 
 +        album: "Amaranthe" 
 +        year: 2011 
 +        cover: "qrc:/button-press.png" 
 +    } 
 +    ListElement 
 +    { 
 +        artist: "Dark Princess" 
 +        album: "Without" 
 +        year: 2005 
 +        cover: "qrc:/button.png" 
 +    } 
 +    ListElement 
 +    { 
 +        artist: "Within" 
 +        album: "The Unfo" 
 +        year: 2011 
 +        cover: "qrc:/atom.png" 
 +    } 
 +
 +</code> 
 +</details> 
 + 
 +  
 +=== XML-модель === 
 +**XmlListModel**- тоже модель списка и используется для XML-данных. Задействует для заполнения данными опросы **XPath** и присваивает данные свойствам.\\ 
 +Для каждого определяемого свойства, определяем **XmlRole**, что является фактом создания св-ва, задаем ему **name**, а так же путь откуда извлечь и тип извлекаемых данных.\\ 
 + 
 +<details> 
 +<summary>:!: Пример: Описание Xml-модели</summary> 
 +<code XML> 
 +<?xml version = "1.0"?> 
 +<CDs> 
 + <CD> 
 + <artist>Amaranthe</artist> 
 + <album>Amaranthe</album> 
 + <year>2011</year> 
 + <cover>qrc:/button-press.png</cover> 
 + </CD> 
 + <CD> 
 + <artist>Dark Princess</artist> 
 + <album>Without</album> 
 + <year>2005</year> 
 + <cover>qrc:/button.png</cover> 
 + </CD> 
 + <CD> 
 + <artist>Within</artist> 
 + <album>The Unfo</album> 
 + <year>2011</year> 
 + <cover>qrc:/atom.png</cover> 
 + </CD> 
 +</CDs> 
 +</code> 
 + 
 +<code QML> 
 +import QtQuick 2.8; import QtQuick.XmlListModel 2.0 
 + 
 +XmlListModel 
 +
 +    source: "qrc:/CDs.xml" 
 +    query: "/CDs/CD" 
 +    XmlRole { name: "artist"; query: "artist/string()"
 +    XmlRole { name: "album"; query: "album/string()"
 +    XmlRole { name: "year"; query: "year/string()"
 +    XmlRole { name: "cover"; query: "cover/string()"
 +
 +</code> 
 +</details> 
 + 
 +  
 +=== JSON-модель === 
 +---- 
 +Благодаря поддержке **JavaScript**, данные **JSON** можно использовать напрямую, например присвоить переменной и далее работать с ней.\\ 
 + 
 +<details> 
 +<summary>:!: Пример: JSON модель</summary> 
 +<code QML> 
 +import QtQuick 2.8; 
 + 
 +var jsonModel = [ 
 +    { 
 +        artist: "Amaranthe", 
 +        album: "Amaranthe", 
 +        year: 2011, 
 +        cover: "qrc:/button-press.png", 
 +    }, 
 +    { 
 +        artist: "Dark Princess", 
 +        album: "Without", 
 +        year: 2005, 
 +        cover: "qrc:/button.png", 
 +    } 
 +    , 
 +    { 
 +        artist: "Within", 
 +        album: "The Unfo", 
 +        year: 2011, 
 +        cover: "qrc:/atom.png", 
 +    } 
 +
 +</code> 
 +</details> 
 + 
 +  
 +==== Представление данных ==== 
 +==ListView ===
 ---- ----
 +Отвечает за отображение данных модели в виде столбца или строки.\\
 +За отображение каждого элемента списка в отдельности отвечает **делегат**.\\
  
 +В примере, в роли делегата реализуем элемент **Component**, со свойством **id**, что бы можно было на него сослаться, в блоке **Item** определяем как будет отображаться каждый элемент нашего списка.\\
 +Далее определяем собсна саму модель **ListView**, в ней ставим **focus**, для навигации клавиатурой, добавляем **header** и **footer**, элемент **highlight** используется для показа текущего элемента. Так же, присваиваем ей определенные ранее модель и делегат.\\
  
 <details> <details>
-<summary>:!: Пример: </summary>+<summary>:!: Пример: Представление данных из JSON</summary>
 <code QML> <code QML>
 +import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0
 +import "qrc:/CDs.js" as CDs
  
 +ApplicationWindow
 +{
 +    width: 200; height: 360; visible: true
 +    Rectangle
 +    {
 +        id: mainrect
 +        anchors.fill: parent
 +        color: "gray"
 +        Component
 +        {
 +            id: delegate
 +            Item
 +            {
 +                width: mainrect.width; height: 70
 +                Row
 +                {
 +                    anchors.verticalCenter: parent.verticalCenter
 +                    Image
 +                    {
 +                        width: 64; height: 64
 +                        source: modelData.cover
 +                        smooth: true
 +                    }
 +                    Column
 +                    {
 +                        Text
 +                        {
 +                            color: "white"
 +                            text: modelData.artist
 +                            font.pointSize: 12
 +                        }
 +                        Text
 +                        {
 +                            color: "lightblue"
 +                            text: modelData.album
 +                            font.pointSize: 10
 +                        }
 +                        Text
 +                        {
 +                            color: "yellow"
 +                            text: modelData.year
 +                            font.pointSize: 8
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +        ListView
 +        {
 +            focus: true
 +            header: Rectangle
 +            {
 +                width: parent.width; height: 30
 +                gradient: Gradient
 +                {
 +                    GradientStop { position: 0; color: "gray" }
 +                    GradientStop { position: 0.7; color: "black" }
 +                }
 +                Text
 +                {
 +                    anchors.centerIn: parent
 +                    color: "gray"; text: "CDs"
 +                    font.bold: true; font.pointSize: 20
 +                }
 +            }
 +            footer: Rectangle
 +            {
 +                width: parent.width; height: 30
 +                gradient: Gradient
 +                {
 +                    GradientStop { position: 0; color: "gray" }
 +                    GradientStop { position: 0.7; color: "black" }
 +                }
 +            }
 +            highlight: Rectangle
 +            {
 +                width: parent.width
 +                color: "darkblue"
 +            }
 +            anchors.fill: parent
 +            model: CDs.jsonModel
 +            delegate: delegate
 +        }
 +    }
 +}
 </code> </code>
 </details> </details>
  
 + 
 +=== GridView ===
 +----
 +**GridView** автоматически заполняет всю область элементами в табличном порядке, поэтому нет необходимости указывать кол-во строк/столбов.\\
 +Использование почти полностью идентично предыдущему примеру, разве что в делегате данные располагаются вертикально.\\
  
 +<details>
 +<summary>:!: Пример: Представление данных из JSON</summary>
 +<code QML>
 +import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0
 +import "qrc:/CDs.js" as CDs
  
 +ApplicationWindow
 +{
 +    width: 380; height: 420; visible: true
 +    Rectangle
 +    {
 +        id: mainrect
 +        anchors.fill: parent
 +        color: "gray"
 +        Component
 +        {
 +            id: delegate
 +            Item
 +            {
 +                width: 120; height: 120
 +                Column
 +                {
 +                    anchors.centerIn: parent
 +                    Image
 +                    {
 +                        anchors.horizontalCenter: parent.horizontalCenter
 +                        width: 64; height: 64
 +                        source: modelData.cover
 +                        smooth: true
 +                    }
 +                    Text
 +                    {
 +                        color: "white"; text: modelData.artist; font.pointSize: 12
 +                    }
 +                    Text
 +                    {
 +                        color: "lightblue"; text: modelData.album; font.pointSize: 10
 +                    }
 +                    Text
 +                    {
 +                        color: "yellow"; text: modelData.year; font.pointSize: 8
 +                    }
 +                }
 +            }
 +        }
 +        GridView
 +        {
 +            cellWidth: 120; cellHeight: 120
 +            focus: true
 +            header: Rectangle
 +            {
 +                width: parent.width; height: 30
 +                gradient: Gradient
 +                {
 +                    GradientStop { position: 0; color: "gray" }
 +                    GradientStop { position: 0.7; color: "black" }
 +                }
 +                Text
 +                {
 +                    anchors.centerIn: parent
 +                    color: "gray"; text: "CDs"
 +                    font.bold: true; font.pointSize: 20
 +                }
 +            }
 +            footer: Rectangle
 +            {
 +                width: parent.width; height: 30
 +                gradient: Gradient
 +                {
 +                    GradientStop { position: 0; color: "gray" }
 +                    GradientStop { position: 0.7; color: "black" }
 +                }
 +            }
 +            highlight: Rectangle
 +            {
 +                width: parent.width
 +                color: "darkblue"
 +            }
 +            anchors.fill: parent
 +            model: CDs.jsonModel
 +            delegate: delegate
 +        }
 +    }
 +}
 +</code>
 +</details>
  
-====  ====+  
 +=== PathView ===
 ---- ----
 +Показывает элементы в виде замкнутой линии.\\
  
 +Делегат идентичен предыдущим. ключевой момент в создании элемента **Path**, этот элемент задает форму замкнутой линии, он присваивается свойству **path** элемента **PathView**, свойство **pathItemCount** определяет кол-во одновременно видимых элементов.\\
  
 <details> <details>
-<summary>:!: Пример: </summary>+<summary>:!: Пример: PathView JSON</summary>
 <code QML> <code QML>
 +import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0
 +import "qrc:/CDs.js" as CDs
  
 +ApplicationWindow
 +{
 +    width: 450; height: 170; visible: true
 +    Rectangle
 +    {
 +        anchors.fill: parent
 +        color: "gray"
 +        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: "white"; text: modelData.artist; font.pointSize: 12
 +                    }
 +                    Text
 +                    {
 +                        color: "lightblue"; text: modelData.album; font.pointSize: 10
 +                    }
 +                    Text
 +                    {
 +                        color: "yellow"; text: modelData.year; font.pointSize: 8
 +                    }
 +                }
 +            }
 +        }
 +        Path
 +        {
 +            id: itemsPath
 +            startX: 45; startY: 80 // Не совсем понятны эти значения
 +            PathLine {x: 500; y: 80} // И эти тоже
 +        }
 +        PathView
 +        {
 +            id: itemsView
 +            focus: true
 +            anchors.fill: parent
 +            model: CDs.jsonModel
 +            delegate: delegate
 +            path: itemsPath
 +            pathItemCount: 4
 +        }
 +    }
 +}
 </code> </code>
 </details> </details>
  
 +Пример прикольной компоновки для предыдущего примера, но работает криво :(
 +<details>
 +<summary>:!: Пример: Вариант компоновки</summary>
 +<code QML>
 +Path
 +{
 +    id: itemsPath
 +    startX: 150; startY: 150
 +    PathAttribute { name: "iconScale"; value: 1.0 }
 +    PathAttribute { name: "iconOpacity"; value: 1.0 }
 +    PathQuad { x: 150; y: 25; controlX: 460; controlY: 75 }
 +    PathAttribute { name: "iconScale"; value: 0.3 }
 +    PathAttribute { name: "iconOpacity"; value: 0.3 }
 +    PathQuad { x: 150; y: 150; controlX: -80; controlY: 75 }
 +}
 +</code>
 +</details>
  
 + 
 +==== Визуальная модель данных ====
 +----
 +**VisualItemModel** - модель которая не нуждается в делегате и сама отвечает за представление своих данных, плюс в том, что каждый элемент может быть **отображен в индивидуальной манере**.\\
  
 +<details>
 +<summary>:!: Пример: Отображение VisualItemModel</summary>
 +<code QML>
 +// Отдельный файл с данными
 +import QtQuick 2.12
 +
 +VisualItemModel
 +{
 +    Row
 +    {
 +        Image
 +        {
 +            width: 64; height: 64
 +            source: "qrc:/button.png"
 +            smooth: true
 +        }
 +        Column
 +        {
 +            Text { color: "white"; text: "111"; font.pointSize: 12 }
 +            Text { color: "lightblue"; text: "112"; font.pointSize: 10 }
 +            Text { color: "yellow"; text: "113"; font.pointSize: 8 }
 +        }
 +    }
 +    Rectangle
 +    {
 +        width: parent.width; height: 64
 +        color: "yellow"
 +        Text
 +        {
 +            anchors.centerIn: parent
 +            color: "red"
 +            text: "Blank"
 +        }
 +    }
 +    Row
 +    {
 +        Image
 +        {
 +            width: 64; height: 64
 +            source: "qrc:/button-press.png"
 +            smooth: true
 +        }
 +        Column
 +        {
 +            Text { color: "white"; text: "221"; font.pointSize: 12 }
 +            Text { color: "lightblue"; text: "222"; font.pointSize: 10 }
 +            Text { color: "yellow"; text: "223"; font.pointSize: 8 }
 +        }
 +    }
 +
 +}
 +
 +// Основной файл программы
 +import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0
 +import "qrc:/CDs.js" as CDs
 +
 +ApplicationWindow
 +{
 +    width: 250; height: 250; visible: true
 +    Rectangle
 +    {
 +        anchors.fill: parent
 +        color: "DarkSlateGray"
 +        Flickable
 +        {
 +            id: view
 +            width: 250; height: 500
 +            contentWidth: 250; contentHeight: column.height
 +            anchors.fill: parent
 +            Column
 +            {
 +                id: column
 +                anchors.fill: view
 +                spacing: 5
 +                Repeater
 +                {
 +                    model: CDs{}
 +                }
 +            }
 +        }
 +    }
 +}
 +</code>
 +</details>
  
-====  ====+  
 +===== Qt Quick и C++ ===== 
 +==== Использование языка QML в C++ ====
 ---- ----
 +В QML интегрирован класс **QQuickWidget**, который наследуется от **QWidget** т.е. является обычным виджетом и хорошо подходит для отображения QML-элементов.\\
 +Расположен он в модуле **quickwidgets**, который необходимо добавлять в **pro-файл**.\\
  
 +<details>
 +<summary>:!: Пример: использование QML как виджет в С++</summary>
 +
 +**pro-файл** содержит: "QT += core gui quick qml quickwidgets".\\
 +
 +Файл **"myWidget.h"**
 +<code cpp-qt>
 +#ifndef MYWIDGET_H
 +#define MYWIDGET_H
 +
 +#include <QWidget>
 +#include <QQuickWidget>
 +#include <QVBoxLayout>
 +
 +class MyWidget : public QWidget
 +{
 +    Q_OBJECT
 +
 +public:
 +    MyWidget(QWidget *parent = nullptr);
 +    ~MyWidget();
 +};
 +#endif // MYWIDGET_H
 +</code>
 +
 +
 +Файл **"myWidget.cpp"**
 +<code cpp-qt>
 +#include "mywidget.h"
 +
 +MyWidget::MyWidget(QWidget *parent): QWidget(parent)
 +{
 +    QQuickWidget* pv= new QQuickWidget(QUrl("qrc:/main.qml"));
 +    QVBoxLayout* pvbox= new QVBoxLayout;
 +    pvbox->addWidget(pv);
 +    setLayout(pvbox);
 +}
 +
 +MyWidget::~MyWidget()
 +{
 +}
 +</code>
 +
 +
 +Файл элемента QML, **main.qml**, добавленный в ресурсы
 +<code QML>
 +import QtQuick 2.0
 +
 +Rectangle
 +{
 +    color: "lightgreen"
 +    width: 100; height: 100
 +    Text
 +    {
 +        objectName: "text"
 +        anchors.centerIn: parent
 +        text: "Hello QML"
 +        
 +        function setFontSize(newSize)
 +        {
 +            font.pixelSize= newSize
 +            return font.family + " Size= "+ newSize
 +        }
 +    }
 +}
 +</code>
 +</details>
 +
 + 
 +=== Взаимодействие из C++ со св-вами элементов QML ===
 +----
 +Базовый QML элемент **Item** реализован в C++ классом **QQuickItem**, который унаследован от **QObject**, наравне с QWidget.\\
 +Через свойство **objectName**, указанное в QML, можно получить доступ к объекту класса **QQuickItem** и с ним можно работать как с обычным объектом **QObject**.\\
 +
 +В следующем примере (на базе предыдущего), с помощью вызова **QQuickWidget::rootObject()** мы получаем указатель на узловой объект **QQuickItem** (в данном случае это Rectangle).\\
 +Далее у этого объекта, с помощью методов **setProperty()** устанавливаем/изменяем нужные свойства.\\
 +С помощью метода **findChild()** мы можем получить указатели на дочерние элементы, и так же доступ к их свойствам.\\
 +
 +Затем вызываем пользовательскую JavaScript функцию из **QML**:\\
 +Все функции в QML представлены в метаобъектной информации, благодаря этом могут быть вызваны из C++, с помощью метода **QMetaObject::invokeMethod()**.\\
 +В этот метод мы передаем указатель на объект, содержащий ф-ю, затем имя функ-ции, в макросе **Q_RETURN_ARG** передается переменная для результата, последними передаются макросы с аргументами- **Q_ARG**, равное кол-ву принимаемых аргументов. Тип данных используется **QVariant**.\\ 
 +
 +<details>
 +<summary>:!: Пример: Изменение св-в элементов QML и вызов функции, из C++</summary>
 +На основании предыдущего примера, файл **myWidget.cpp**
 +<code cpp-qt>
 +MyWidget::MyWidget(QWidget *parent): QWidget(parent)
 +{
 +    QQuickWidget* pv= new QQuickWidget(QUrl("qrc:/main.qml"));
 +    QVBoxLayout* pvbox= new QVBoxLayout;
 +    pvbox->addWidget(pv);
 +    setLayout(pvbox);
 +
 +    QQuickItem *pqiRoot= pv->rootObject();
 +    if(pqiRoot)
 +    {
 +        pqiRoot->setProperty("color", "yellow");
 +        QObject *pObjText= pqiRoot->findChild<QObject*>("text");
 +        if(pObjText)
 +        {
 +            pObjText->setProperty("text", "C++");
 +            pObjText->setProperty("color", "blue");
 +            QVariant varRet;
 +            QMetaObject::invokeMethod(pObjText, "setFontSize", Q_RETURN_ARG(QVariant, varRet), Q_ARG(QVariant, 52));
 +            qDebug() << varRet;
 +        }
 +    }
 +}
 +</code>
 +</details>
 +
 + 
 +=== Соединение QML-сигналов со слотами C++ ===
 +----
 +В прошлых примерах мы использовали QML внутри виджетов, теперь мы исключим их и уберем лишние зависимости.\\
 +На этот раз вся **форма** будет **QML**, на **C++** реализованы **действия** по нажатию кнопок.\\
  
 +В проект добавлены только 2 модуля: **"QT += quick qml"**
 <details> <details>
-<summary>:!: Пример: </summary>+<summary>:!: Пример: Соединение сигналов с QML формы со слотами C++ класса</summary> 
 +**Форма приложения**
 <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: parent
 +        spacing: 5
 +        Button
 +        {
 +            signal infoClick(string str)
 +            objectName: "InfoButton"
 +            text: "Info"
 +            onClicked: infoClick("Information")
 +        }
 +        Button
 +        {
 +            signal quitClick()
 +            objectName: "QuitButton"
 +            text: "Quit"
 +            onClicked: quitClick()
 +        }
 +    }
 +}
 +</code>
 +
 +**Класс со слотами**
 +<code cpp-qt>
 +#ifndef MYWIDGET_H
 +#define MYWIDGET_H
 +
 +#include <QtCore>
 +
 +class CppConnect : public QObject
 +{
 +    Q_OBJECT
 +
 +public:
 +    CppConnect(QObject *parent = nullptr)
 +    {
 +    }
 +
 +public slots:
 +    void slotQuit()
 +    {
 +        qApp->quit();
 +    }
 +
 +    void slotInfo(const QString str)
 +    {
 +        qDebug() << str;
 +    }
 +
 +};
 +#endif // MYWIDGET_H
 +</code>
 +
 +**Соединение сигналов со слотами, ф-я main**
 +<code cpp-qt>
 +#include <QGuiApplication>
 +#include <QQmlApplicationEngine>
 +#include <QQmlComponent>
 +#include "mywidget.h"
 +
 +int main(int argc, char** argv)
 +{
 +    QGuiApplication app(argc, argv);
 +    QQmlApplicationEngine eng;
 +    QQmlComponent comp(&eng, QUrl("qrc:/main.qml"));
 +    CppConnect cc;
 +    QObject *pobj= comp.create();
 +
 +    QObject *pcmdQuitButton= pobj->findChild<QObject*>("QuitButton");
 +    if(pcmdQuitButton)
 +    {
 +        QObject::connect(pcmdQuitButton, SIGNAL(quitClick()), &cc, SLOT(slotQuit()));
 +    }
 +
 +    QObject *pcmdInfoButton= pobj->findChild<QObject*>("InfoButton");
 +    if(pcmdInfoButton)
 +    {
 +        QObject::connect(pcmdInfoButton, SIGNAL(infoClick(QString)), &cc, SLOT(slotInfo(QString)));
 +    }
 +    return app.exec();
 +}
 </code> </code>
 </details> </details>
  
 + 
 +==== Использование компонентов C++ в QML ====
 +----
 +В QML реализована возможность расширения при помощи C++, благодаря этому можно QML расширять новыми элементами из C++.\\
 +Существующие технологии импортируются директивой **import**, например "import QtWebEngine 1.5".\\
 +
 +Работа происходит через класс контекста **QQmlContext**, что бы получить доступ к объекту этого класса, нужно из объекта класса **QQuickWidget** вызвать метод **rootContext()**, который вернет указатель на корневой контекст.\\
 +Используя этот указатель вы можете ввести в дерево контекста новые объекты классов, унаследованных от **QObject**. Публикация происходит с помощью метода **setContextProperty()**, он принимает имя объекта и собсна адрес самого объекта.\\
 +После этого, свойства класса **QObject** станут свойствами QML, а слоты и методы (декларированные с Q_INVOKABLE) смогут вызываться из вашего QML-элемента.\\
 +Класс **QQuickWidget** так же содержит объект класса **QQmlEngine** (вызов engine()), который предоставляет среду для исполнения QML.\\
 +
 + 
 +=== Экспорт объектов и виджетов из C++ в QML ===
 +----
 +Пример экспорта, создаем C++ класс, в конструкторе делаем загрузку и отображение QML формы, виджетом и создаем несколько локальных объектов, которые экспортируются в QML форму, так же экспортируется и объект самого класса (this), определяем слот, все это будет **доступно в QML форме**.\\
 +
 +<details>
 +<summary>:!: Пример: Экспорт объектов в QML</summary>
 +**Файл класса myWidget.cpp**
 +<code cpp-qt>
 +#include "mywidget.h"
 +
 +MyWidget::MyWidget(QWidget *parent): QWidget(parent)
 +{
 +    QQuickWidget *pv= new QQuickWidget(this);
 +    pv->setSource(QUrl("qrc:/main.qml"));
 +
 +    QVBoxLayout *pvbx= new QVBoxLayout(this);
 +    pvbx->addWidget(pv);
 +    setLayout(pvbx);
 +
 +    QQmlContext *pcon= pv->rootContext();
 +    QStringList lst;
 +    for(int i= 0; i < 100; i++)
 +        lst << "Item"+ QString::number(i);
 +    QStringListModel *pmodel= new QStringListModel(this);
 +    pmodel->setStringList(lst);
 +
 +    pcon->setContextProperty("myModel", pmodel);
 +    pcon->setContextProperty("myText", "It's my text");
 +    pcon->setContextProperty("myColor", QColor(Qt::yellow));
 +    pcon->setContextProperty("myWidget", this);
 +}
 +
 +void MyWidget::slotDisplayDialog()
 +{
 +    QMessageBox::information(0, "Title Message", "Text in message");
 +}
 +</code>
 +
 +
 +**Форма QML**
 +<code QML>
 +import QtQuick 2.8
 +
 +Rectangle
 +{
 +    width: 200; height: 200;
 +    color: myColor
 +    Text
 +    {
 +        anchors.centerIn: parent
 +        text: myText
 +    }
 +    ListView
 +    {
 +        anchors.fill: parent
 +        model: myModel
 +        delegate: Text { text: model.display }
 +    }
 +    MouseArea
 +    {
 +        anchors.fill: parent
 +        onPressed:
 +        {
 +            myWidget.setWindowTitle("Hello from QML");
 +            myWidget.slotDisplayDialog();
 +        }
 +    }
 +}
 +</code>
 +</details>
 +
 + 
 +=== Использование зарегистр объектов C++ в QML ===
 +----
 +Как я понял, это передача в QML только **конкретных свойств и методов**, определенных директивами **Q_PROPERTY** и **Q_INVOKABLE** соответственно.\\
 +Прежде всего производим регистрацию нашего класса, функцией **qmlRegisterType<T>()**, в нее передается идентификатор модуля (похоже собственный), два параметра с номерами версии, и собсна имя самого класса.\\
 +
 +<details>
 +<summary>:!: Пример: Передача свойств, методов и сигналов класса в QML</summary>
 +**Calculate.h**
 +<code cpp-qt>
 +#ifndef CALCULATION_H
 +#define CALCULATION_H
 +
 +#include <QObject>
 +
 +class Calculation : public QObject
 +{
 +    Q_OBJECT
 +private:
 +    Q_PROPERTY(qulonglong input WRITE setInputValue
 +                                READ inputValue
 +                                NOTIFY inputValueChanged) // Уведомление об изменении
 +    Q_PROPERTY(qulonglong result READ resultValue
 +                                 NOTIFY inputValueChanged)
 +    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
 +</code>
 +
 +
 +**Calculate.cpp**
 +<code cpp-qt>
 +#include "calculation.h"
 +
 +Calculation::Calculation(QObject *parent) : QObject(parent), m_nInput(0), m_nResult(1)
 +{
 +}
 +
 +qulonglong Calculation::factorial(const qulonglong &n)
 +{
 +    return n ? (n * factorial(n-1)) : 1;
 +}
 +
 +qulonglong Calculation::inputValue() const
 +{
 +    return m_nInput;
 +}
 +
 +qulonglong Calculation::resultValue() const
 +{
 +    return m_nResult;
 +}
 +
 +void Calculation::setInputValue(const qulonglong &n)
 +{
 +    m_nInput= n;
 +    m_nResult= factorial(m_nInput);
 +    emit inputValueChanged(m_nInput);
 +    emit resultValueChanged(m_nResult);
 +}
 +</code>
 +
 +**main.cpp**
 +<code cpp-qt>
 +#include <QGuiApplication>
 +#include <QQmlApplicationEngine>
 +#include "calculation.h"
 +
 +int main(int argc, char** argv)
 +{
 +    QGuiApplication app(argc, argv);
 +    qmlRegisterType<Calculation>("my.class.Calc", 1, 0, "Calculatoin");
 +    QQmlApplicationEngine engine;
 +    engine.load(QUrl("qrc:/main.qml"));
 +
 +    return app.exec();
 +}
 +</code>
 +
 +
 +**Два варианта** реализации, свойствами и методом
 +<code QML>
 +import QtQuick 2.8; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.3;
 +import my.class.Calc 1.0
 +
 +ApplicationWindow
 +{
 +    title: "Factorial Calc"; width: 250; height: 80;
 +    visible: true
 +    Calculation
 +    {
 +        id: calc
 +    }
 +    ColumnLayout
 +    {
 +        anchors.fill: parent
 +        RowLayout // Первый подход, с использованием метода
 +        {
 +            SpinBox
 +            {
 +                id: sbx
 +                value: 0
 +            }
 +            Text
 +            {
 +                text: "Result: "+ calc.factorial(sbx.value)
 +            }
 +        }
 +        RowLayout // Второй подход, с использованием свойств
 +        {
 +            SpinBox
 +            {
 +                value: 0
 +                onValueChanged: calc.input= value
 +            }
 +            Text
 +            {
 +                text: "Result: "+ calc.result
 +            }
 +        }
 +    }
 +}
 +</code>
 +
 +
 +**Альтернативный подход** с использованием сигналов
 +<code QML>
 +import QtQuick 2.8; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.3;
 +import my.class.Calc 1.0
 +
 +ApplicationWindow
 +{
 +    title: "Factorial Calc"; width: 250; height: 80;
 +    visible: true
 +    Calculatoin
 +    {
 +        input: sbx.value
 +        onResultValueChanged: txt.text= "Result: "+ result
 +    }
 +    RowLayout
 +    {
 +        SpinBox
 +        {
 +            id: sbx
 +            value: 0
 +        }
 +        Text
 +        {
 +            id: txt
 +        }
 +    }
 +}
 +</code>
 +</details>
 +
 + 
 +=== Реализация визуальных элементов QML на C++ ===
 +----
 +Все базовые **элементы QML** (такие как Rectangle или Text), **реализованы на C++** (QQuickRectangle, QQuickText), унаследованы они от **QQuickItem**, для собственной реализации нужно наследовать этот класс, но есть спец подготовленный для этого- **QQuickPaintedItem**, он уже унаследован.\\
 +
 +<details>
 +<summary>:!: Пример: Собственный элемент, эллипс</summary>
 +**Ellipse.h**
 +<code cpp-qt>
 +#ifndef ELLIPSE_H
 +#define ELLIPSE_H
 +
 +#include <QQuickPaintedItem>
 +
 +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
 +</code>
 +
 +
 +**Ellipse.hpp**
 +<code cpp-qt>
 +#include "ellipse.h"
 +#include <QPainter>
 +
 +Ellipse::Ellipse(QQuickItem *parent): QQuickPaintedItem(parent), m_color(Qt::black)
 +{
 +}
 +
 +void Ellipse::paint(QPainter *ppainter)
 +{
 +    ppainter->setRenderHint(QPainter::Antialiasing, true);
 +    ppainter->setBrush(QBrush(this->colorValue()));
 +    ppainter->setPen(Qt::NoPen);
 +    ppainter->drawEllipse(boundingRect());
 +}
 +
 +QColor Ellipse::colorValue() const
 +{
 +    return this->m_color;
 +}
 +
 +void Ellipse::setColorValue(const QColor &vCol)
 +{
 +    this->m_color= vCol;
 +}
 +</code>
 +
 +
 +**main.hpp**
 +<code cpp-qt>
 +#include <QGuiApplication>
 +#include <QQmlApplicationEngine>
 +#include "ellipse.h"
 +
 +int main(int argc, char** argv)
 +{
 +    QGuiApplication app(argc, argv);
 +    qmlRegisterType<Ellipse>("my.class.Ellipse", 1, 0, "Ellipse");
 +    QQmlApplicationEngine engine;
 +    engine.load(QUrl("qrc:/main.qml"));
 +
 +    return app.exec();
 +}
 +</code>
 +
 +
 +**main.qml**
 +<code QML>
 +import QtQuick 2.8; import QtQuick.Controls 2.2
 +import my.class.Ellipse 1.0
 +
 +ApplicationWindow
 +{
 +    title: "Paint Element"; width: 200; height: 100;
 +    visible: true
 +    Ellipse
 +    {
 +        anchors.fill: parent
 +        color: "blue"
 +    }
 +}
 +</code>
 +</details>
 +
 + 
 +=== Класс QQuickImageProvider ====
 +----
 +Этот класс является неким объектом, который возвращает запрашиваемое изображение (QImage либо QPixmap), запрашивается оно из QML по имени файла (либо какой-нибудь условный идентификатор), зарегистрированный ImageProvider типа папка, а идентификатор имя файла.\\
 +Т.к. ImageProvider возвращает (методом request) изображение в как таковом виде (тип данных image/pixmap), его можно всячески модифицировать перед отправкой, или даже вовсе создать в этом методе, либо организовать некую логику, на основании переданных данных например..\\
 +
 +<details>
 +<summary>:!: Пример: Яркость изображения</summary>
 +
 +**ImageProvider.h**
 +<code cpp-qt>
 +#ifndef IMAGEPROVIDER_H
 +#define IMAGEPROVIDER_H
 +#include <QQuickImageProvider>
 +#include <QObject>
 +#include <QImage>
 +
 +class ImageProvider: public QQuickImageProvider
 +{
 +private:
 +    QImage brightness(const QImage &imgOrig, int n);
 +
 +public:
 +    ImageProvider();
 +    QImage requestImage(const QString&, QSize*, const QSize&);
 +};
 +
 +#endif // IMAGEPROVIDER_H
 +</code>
 +
 +
 +**ImageProvider.hpp**
 +<code cpp-qt>
 +#include "imageprovider.h"
 +
 +ImageProvider::ImageProvider(): QQuickImageProvider(QQuickImageProvider::Image)
 +{
 +}
 +
 +QImage ImageProvider::brightness(const QImage &imgOrig, int n)
 +{
 +    QImage imgTemp= imgOrig;
 +    qint32 nHeigt= imgTemp.height();
 +    qint32 nWidth= imgTemp.width();
 +
 +    for(qint32 y= 0; y < nHeigt; ++y)
 +    {
 +        QRgb *tempLine= reinterpret_cast<QRgb*>(imgTemp.scanLine(y));
 +        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::requestImage(const QString &strId, QSize *ps, const QSize &requestedSize)
 +{
 +    QStringList lst= strId.split(";");
 +    bool bOk= false;
 +    int nBrightness= lst.last().toInt(&bOk);
 +    QImage img= brightness(QImage(":/"+ lst.first()), nBrightness);
 +
 +    if(ps)
 +        *ps= img.size();
 +
 +    return img;
 +}
 +</code>
 +
 +
 +**main.hpp**
 +<code cpp-qt>
 +#include <QGuiApplication>
 +#include <QQmlApplicationEngine>
 +#include "imageprovider.h"
 +
 +int main(int argc, char** argv)
 +{
 +    QGuiApplication app(argc, argv);
 +    QQmlApplicationEngine engine;
 +    engine.addImageProvider(QLatin1String("brightness"), new ImageProvider);
 +    engine.load(QUrl("qrc:/main.qml"));
 +
 +    return app.exec();
 +}
 +</code>
 +
 +
 +**main.qml**
 +<code QML>
 +import QtQuick 2.8; import QtQuick.Controls 2.2
 +
 +ApplicationWindow
 +{
 +    title: "Brightness"; width: controls.width; height: controls.height;
 +    visible: true
 +    Column
 +    {
 +        id: controls
 +        Image
 +        {
 +            id: img
 +            source: "image://brightness/11.jpg;"+ sld.brightnessValue
 +        }
 +        Slider
 +        {
 +            id: sld
 +            width: img.width
 +            value: 0.75
 +            stepSize: 0.01
 +            property int brightnessValue: (value * 255 -127)
 +        }
 +        Text
 +        {
 +            width: img.width
 +            text: "<h1>Brightness: "+ sld.brightnessValue+ "</h1>"
 +        }
 +    }
 +}
 +</code>
 +</details>
develop/qt/quick3.1630246102.txt.gz · Последнее изменение: 2021/08/29 14:08 — admin