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

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


develop:qt:quick3

Это старая версия документа!


Qt Quick: Модель/Представление, Связь с С++

Модель/Представление

В QML предоставляет механизм отделения данных от их представления. За показ отвечают элементы представления и делегаты, а за поставку- элементы моделей.

Модели

Модель - предоставляет интерфейс для обращения к данным, может содержать и сами данные, но не обязательно.

Модель списка

Представлена элементом ListModel и содержит последовательность элементов: ListElement{…} ….
ListElement содержит свойства данных, все они определяются пользователем, стандартных нет.
Элементы можно описывать как вручную, так и динамически, поддерживаются функции типа: append(), insert(), remove(), move и т.д.

:!: Пример: Статическое описание содержимого модели
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"
    }
}

 

XML-модель

XmlListModel- тоже модель списка и используется для XML-данных. Задействует для заполнения данными опросы XPath и присваивает данные свойствам.
Для каждого определяемого свойства, определяем XmlRole, что является фактом создания св-ва, задаем ему name, а так же путь откуда извлечь и тип извлекаемых данных.

:!: Пример: Описание 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>
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()" }
}

 

JSON-модель


Благодаря поддержке JavaScript, данные JSON можно использовать напрямую, например присвоить переменной и далее работать с ней.

:!: Пример: JSON модель
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",
    }
]

 

Представление данных

ListView


Отвечает за отображение данных модели в виде столбца или строки.
За отображение каждого элемента списка в отдельности отвечает делегат.

В примере, в роли делегата реализуем элемент Component, со свойством id, что бы можно было на него сослаться, в блоке Item определяем как будет отображаться каждый элемент нашего списка.
Далее определяем собсна саму модель ListView, в ней ставим focus, для навигации клавиатурой, добавляем header и footer, элемент highlight используется для показа текущего элемента. Так же, присваиваем ей определенные ранее модель и делегат.

:!: Пример: Представление данных из JSON
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
        }
    }
}

 

GridView


GridView автоматически заполняет всю область элементами в табличном порядке, поэтому нет необходимости указывать кол-во строк/столбов.
Использование почти полностью идентично предыдущему примеру, разве что в делегате данные располагаются вертикально.

:!: Пример: Представление данных из JSON
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
        }
    }
}

 

PathView


Показывает элементы в виде замкнутой линии.

Делегат идентичен предыдущим. ключевой момент в создании элемента Path, этот элемент задает форму замкнутой линии, он присваивается свойству path элемента PathView, свойство pathItemCount определяет кол-во одновременно видимых элементов.

:!: Пример: PathView JSON
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
        }
    }
}

Пример прикольной компоновки для предыдущего примера, но работает криво :(

:!: Пример: Вариант компоновки
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 }
}

 

Визуальная модель данных


VisualItemModel - модель которая не нуждается в делегате и сама отвечает за представление своих данных, плюс в том, что каждый элемент может быть отображен в индивидуальной манере.

:!: Пример: Отображение VisualItemModel
// Отдельный файл с данными
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{}
                }
            }
        }
    }
}

 

Qt Quick и C++

Использование языка QML в C++


В QML интегрирован класс QQuickWidget, который наследуется от QWidget т.е. является обычным виджетом и хорошо подходит для отображения QML-элементов.
Расположен он в модуле quickwidgets, который необходимо добавлять в pro-файл.

:!: Пример: использование QML как виджет в С++

pro-файл содержит: «QT += core gui quick qml quickwidgets».

Файл «myWidget.h»

#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

Файл «myWidget.cpp»

#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()
{
}

Файл элемента QML, main.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
        }
    }
}

 

Взаимодействие из 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.

:!: Пример: Изменение св-в элементов QML и вызов функции, из C++

На основании предыдущего примера, файл myWidget.cpp

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

 

Соединение QML-сигналов со слотами C++


В прошлых примерах мы использовали QML внутри виджетов, теперь мы исключим их и уберем лишние зависимости.
На этот раз вся форма будет QML, на C++ реализованы действия по нажатию кнопок.

В проект добавлены только 2 модуля: «QT += quick qml»

:!: Пример: Соединение сигналов с QML формы со слотами C++ класса

Форма приложения

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

Класс со слотами

#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

Соединение сигналов со слотами, ф-я main

#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();
}

 

Использование компонентов 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 форме.

:!: Пример: Экспорт объектов в QML

Файл класса myWidget.cpp

 

Форма QML

 

 

Использов зарегистр объектов C++ в QML


:!: Пример:
 

 

Реализация визуальных элементов QML на C++


:!: Пример:
 

 

Класс QQuickImageProvider


:!: Пример:
 
:!: Пример:
 
develop/qt/quick3.1630429213.txt.gz · Последнее изменение: 2021/08/31 17:00 — admin