在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告
Problems with editing C++ QList<Object*> model in Qml code and some Qml warnings
我需要创建一个可以在 C++ 和 Qml 代码中编辑的模型。该模型将用于包含 Qt Widgets 和 Qml 的桌面应用程序。对于 qml 渲染,我使用 QQuickWidget
.
我有两个属性的数据对象:名称和颜色。
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();
}
}
对于主要 window 我使用 QMainWindow
的子类。 Сentral 小部件包含 QQuickWidget
,来源 MainView.qml。在构造函数中,我填充 QList<Object*>
模型并将其设置为上下文 属性 "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 包含一些附加组件(firstTextField、secondComboBox、"Ok" 和 "Cancel" 按钮)和 GroupBox
包含 Repeater
,它使用我的 "nameColorModel". NameColorEdit.qml 用作 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
}
}
}
当我更改 NameColorEdit.qml 的 "nameField" 中的文本时,"nameColorModel" 在 С++ 代码中没有更改。
我该如何解决这个问题?
在qml代码中也有如下警告:
qrc:/MainView.qml:50:9: QML GroupBox: Binding loop detected for
property "implicitWidth" qrc:/MainView.qml:61: ReferenceError:
nameColorModel is not defined
注意模型会在调用QQuickWidget
的setSource后设置。
我该如何修复这些警告?
也可以给我写代码的建议
谢谢!
问题已通过对 DataObject
属性 和 NameColorEdit
使用 Binding
解决 属性:
Repeater {
id: repeater
model: nameColorModel //// <-- QList<Object*> model
Views.NameColorEdit {
name: modelData.name
color: modelData.color
Layout.row: index
Layout.fillWidth: true
Binding { target: modelData; property: "name"; value: name }
Binding { target: modelData; property: "color"; value: color }
}
}
现在,当在 C++ 代码中编辑 QList<Object*>
模型的 NameColorEdit.qml 内容中的 nameField 时,已成功更新。此外,如果我们在 C++ 代码中更改 QList<Object*>
模型的内容,NameColorEdit.qml 将被更新。
我需要创建一个可以在 C++ 和 Qml 代码中编辑的模型。该模型将用于包含 Qt Widgets 和 Qml 的桌面应用程序。对于 qml 渲染,我使用 QQuickWidget
.
我有两个属性的数据对象:名称和颜色。
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();
}
}
对于主要 window 我使用 QMainWindow
的子类。 Сentral 小部件包含 QQuickWidget
,来源 MainView.qml。在构造函数中,我填充 QList<Object*>
模型并将其设置为上下文 属性 "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 包含一些附加组件(firstTextField、secondComboBox、"Ok" 和 "Cancel" 按钮)和 GroupBox
包含 Repeater
,它使用我的 "nameColorModel". NameColorEdit.qml 用作 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
}
}
}
当我更改 NameColorEdit.qml 的 "nameField" 中的文本时,"nameColorModel" 在 С++ 代码中没有更改。 我该如何解决这个问题?
在qml代码中也有如下警告:
qrc:/MainView.qml:50:9: QML GroupBox: Binding loop detected for property "implicitWidth" qrc:/MainView.qml:61: ReferenceError: nameColorModel is not defined
注意模型会在调用QQuickWidget
的setSource后设置。
我该如何修复这些警告?
也可以给我写代码的建议
谢谢!
问题已通过对 DataObject
属性 和 NameColorEdit
使用 Binding
解决 属性:
Repeater {
id: repeater
model: nameColorModel //// <-- QList<Object*> model
Views.NameColorEdit {
name: modelData.name
color: modelData.color
Layout.row: index
Layout.fillWidth: true
Binding { target: modelData; property: "name"; value: name }
Binding { target: modelData; property: "color"; value: color }
}
}
现在,当在 C++ 代码中编辑 QList<Object*>
模型的 NameColorEdit.qml 内容中的 nameField 时,已成功更新。此外,如果我们在 C++ 代码中更改 QList<Object*>
模型的内容,NameColorEdit.qml 将被更新。