在 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 将被更新。