====== 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-модели
Amaranthe
Amaranthe
2011
qrc:/button-press.png
Dark Princess
Without
2005
qrc:/button.png
Within
The Unfo
2011
qrc:/atom.png
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
#include
#include
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("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
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
#include
#include
#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("QuitButton");
if(pcmdQuitButton)
{
QObject::connect(pcmdQuitButton, SIGNAL(quitClick()), &cc, SLOT(slotQuit()));
}
QObject *pcmdInfoButton= pobj->findChild("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**
#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");
}
**Форма 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();
}
}
}
=== Использование зарегистр объектов C++ в QML ===
----
Как я понял, это передача в QML только **конкретных свойств и методов**, определенных директивами **Q_PROPERTY** и **Q_INVOKABLE** соответственно.\\
Прежде всего производим регистрацию нашего класса, функцией **qmlRegisterType()**, в нее передается идентификатор модуля (похоже собственный), два параметра с номерами версии, и собсна имя самого класса.\\
:!: Пример: Передача свойств, методов и сигналов класса в QML
**Calculate.h**
#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
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
**Calculate.cpp**
#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);
}
**main.cpp**
#include
#include
#include "calculation.h"
int main(int argc, char** argv)
{
QGuiApplication app(argc, argv);
qmlRegisterType("my.class.Calc", 1, 0, "Calculatoin");
QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
**Два варианта** реализации, свойствами и методом
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
}
}
}
}
**Альтернативный подход** с использованием сигналов
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
}
}
}
=== Реализация визуальных элементов QML на C++ ===
----
Все базовые **элементы QML** (такие как Rectangle или Text), **реализованы на C++** (QQuickRectangle, QQuickText), унаследованы они от **QQuickItem**, для собственной реализации нужно наследовать этот класс, но есть спец подготовленный для этого- **QQuickPaintedItem**, он уже унаследован.\\
:!: Пример: Собственный элемент, эллипс
**Ellipse.h**
#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**
#include "ellipse.h"
#include
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;
}
**main.hpp**
#include
#include
#include "ellipse.h"
int main(int argc, char** argv)
{
QGuiApplication app(argc, argv);
qmlRegisterType("my.class.Ellipse", 1, 0, "Ellipse");
QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
**main.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"
}
}
=== Класс QQuickImageProvider ====
----
Этот класс является неким объектом, который возвращает запрашиваемое изображение (QImage либо QPixmap), запрашивается оно из QML по имени файла (либо какой-нибудь условный идентификатор), зарегистрированный ImageProvider типа папка, а идентификатор имя файла.\\
Т.к. ImageProvider возвращает (методом request) изображение в как таковом виде (тип данных image/pixmap), его можно всячески модифицировать перед отправкой, или даже вовсе создать в этом методе, либо организовать некую логику, на основании переданных данных например..\\
:!: Пример: Яркость изображения
**ImageProvider.h**
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include
#include
#include
class ImageProvider: public QQuickImageProvider
{
private:
QImage brightness(const QImage &imgOrig, int n);
public:
ImageProvider();
QImage requestImage(const QString&, QSize*, const QSize&);
};
#endif // IMAGEPROVIDER_H
**ImageProvider.hpp**
#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(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;
}
**main.hpp**
#include
#include
#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();
}
**main.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: "Brightness: "+ sld.brightnessValue+ "
"
}
}
}