====== 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+ "

" } } }