I need to create a model that can be edited in C++ and Qml code. This model will be used in an desktop application that contains both Qt Widgets and Qml. For qml rendering I use the QQuickWidget
.
I have data object with two properties: name and color.
dataobject.h
#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
public:
DataObject(QObject *parent = Q_NULLPTR);
DataObject(const QString &name, const QString &color, QObject *parent = Q_NULLPTR);
QString name() const;
void setName(const QString &name);
QString color() const;
void setColor(const QString &color);
signals:
void nameChanged();
void colorChanged();
private:
QString m_name;
QString m_color;
};
#endif // DATAOBJECT_H
dataobject.cpp
#include "dataobject.h"
#include <QDebug>
DataObject::DataObject(QObject *parent)
: QObject(parent)
{
}
DataObject::DataObject(const QString &name, const QString &color, QObject *parent)
: QObject(parent), m_name(name), m_color(color)
{
}
QString DataObject::name() const
{
return m_name;
}
void DataObject::setName(const QString &name)
{
qDebug() << Q_FUNC_INFO;
if (name != m_name) {
m_name = name;
emit nameChanged();
}
}
QString DataObject::color() const
{
return m_color;
}
void DataObject::setColor(const QString &color)
{
qDebug() << Q_FUNC_INFO;
if (color != m_color) {
m_color = color;
emit colorChanged();
}
}
For the main window I use subclass of QMainWindow
. Сentral widget contains QQuickWidget
with source MainView.qml. In constructor I fill QList<Object*>
model and set it as context property "nameColorModel" for MainView.qml.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = Q_NULLPTR);
~MainWindow();
public slots:
void onAccepted();
private:
QList<QObject*> nameColorModel;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "dataobject.h"
#include <QQuickWidget>
#include <QQmlContext>
#include <QQuickItem>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
auto qmlWidget = new QQuickWidget(QUrl("qrc:/MainView.qml"), this);
qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
this->setCentralWidget(qmlWidget);
this->resize(600, 400);
nameColorModel.append(new DataObject("Item 1", "red"));
nameColorModel.append(new DataObject("Item 2", "green"));
nameColorModel.append(new DataObject("Item 3", "blue"));
nameColorModel.append(new DataObject("Item 4", "yellow"));
qmlWidget->rootContext()->setContextProperty("nameColorModel", QVariant::fromValue(nameColorModel));
connect(qmlWidget->rootObject(), SIGNAL(accepted()), SLOT(onAccepted()));
}
MainWindow::~MainWindow()
{
qDeleteAll(nameColorModel.begin(), nameColorModel.end());
}
void MainWindow::onAccepted()
{
for(auto& object: nameColorModel)
{
auto item = qobject_cast<DataObject*>(object);
qDebug() << item->name() << item->color();
}
}
MainView.qml contains some additional components (firstTextField, secondComboBox, "Ok" and "Cancel" buttons) and GroupBox
containing Repeater
which uses my "nameColorModel". NameColorEdit.qml is used as delegate of Repeater
.
MainView.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
import "." as Views
Item {
id: root
width: 600
height: 400
property alias firstText: firstTextField.text
property alias secondText: secondComboBox.currentText
signal accepted()
signal rejected()
ColumnLayout {
spacing: 10
anchors.fill: parent
anchors.margins: 10
GridLayout {
columns: 2
rowSpacing: 10
columnSpacing: 10
Label {
text: "First"
}
TextField {
id: firstTextField
implicitHeight: 42
Layout.fillWidth: true
}
Label {
text: "Second"
}
ComboBox {
id: secondComboBox
implicitHeight: 42
model: 5
Layout.fillWidth: true
}
}
GroupBox {
title: qsTr("Name-color objects:")
Layout.fillWidth: true
ColumnLayout {
id: col
spacing: 10
anchors.fill: parent
Repeater {
id: repeater
model: nameColorModel //// <-- QList<Object*> model
Views.NameColorEdit {
name: modelData.name
color: modelData.color
Layout.row: index
Layout.fillWidth: true
}
}
}
}
Item {
Layout.fillHeight: true
}
RowLayout {
Layout.alignment: Qt.AlignRight
Button {
text: "Ок"
Layout.minimumWidth: 42
Layout.minimumHeight: 42
onClicked: accepted()
}
Button {
text: "Cancel"
Layout.minimumWidth: 42
Layout.minimumHeight: 42
onClicked: rejected()
}
}
}
}
NameColorEdit.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
Item {
id: root
implicitWidth: nameField.implicitWidth
implicitHeight: nameField.implicitHeight
property alias name: nameField.text
property alias color: colorField.text
RowLayout {
spacing: 10
anchors.fill: parent
Label {
text: "Color"
}
TextField {
id: colorField
enabled: false
implicitWidth: 150
implicitHeight: 42
}
Label {
text: "Name"
}
TextField {
id: nameField
implicitHeight: 42
Layout.fillWidth: true
}
}
}
When I change text in the "nameField" of NameColorEdit.qml, "nameColorModel" doesn't change in С++ code. How can I fix this?
Also there are following warnings in qml code:
qrc:/MainView.qml:50:9: QML GroupBox: Binding loop detected for property "implicitWidth" qrc:/MainView.qml:61: ReferenceError: nameColorModel is not defined
Note that the model will be set after calling setSource of QQuickWidget
.
How can I fix these warnings?
You can also give me recommendations on writing code.
Thank you!