在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告

Posted

技术标签:

【中文标题】在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告【英文标题】:Problems with editing C++ QList<Object*> model in Qml code and some Qml warnings 【发布时间】:2017-03-03 20:54:49 【问题描述】:

我需要创建一个可以在 C++ 和 Qml 代码中编辑的模型。该模型将用于同时包含 Qt Widgets 和 Qml 的桌面应用程序。对于 qml 渲染,我使用QQuickWidget

我有两个属性的数据对象:名称和颜色。

数据对象.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

数据对象.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();
    

对于主窗口,我使用QMainWindow 的子类。 Сentral 小部件包含 QQuickWidget 和源 MainView.qml。在构造函数中,我填写 QList&lt;Object*&gt; 模型并将其设置为 MainView.qml 的上下文属性“nameColorModel”。

主窗口.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

主窗口.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,其中包含使用我的“nameColorModel”的Repeater。 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:检测到绑定循环 属性 "implicitWidth" qrc:/MainView.qml:61: ReferenceError: nameColorModel 未定义

注意模型会在调用QQuickWidget的setSource后设置。 如何解决这些警告?

你也可以给我写代码的建议。

谢谢!

【问题讨论】:

你的视图是在设置上下文属性之前创建的,所以第一次运行会报错nameColorModel。尝试早点设置 context 属性。 您可能还想考虑拥有一个“数据处理程序”类来管理您的值对并为更改通知提供信号,并在 QtWidgets 的表模型和 QtQuick 的列表模型中使用它。或者,为这两种情况提供一个表模型,但将 Q​​ML 属性映射到列中 @arynaq,有没有办法在视图创建后设置上下文属性而不发出警告? @Kevin Krammer,感谢您的推荐! 【参考方案1】:

问题已通过使用Binding 来解决DataObject 属性和NameColorEdit 属性:

        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&lt;Object*&gt; 模型的 NameColorEdit.qml 中的 nameField 内容时已成功更新。此外,如果我们在 C++ 代码中更改 QList&lt;Object*&gt; 模型的内容,NameColorEdit.qml 将被更新。

【讨论】:

以上是关于在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告的主要内容,如果未能解决你的问题,请参考以下文章

在 QML 中读取 QList<QPoint>

QML - 访问存储在 QList 中的 QObject 类属性

QList<int> 不能用作Repeater 的模型

qml 使用中继器从 Qlist 绘制折线图

从 qml 编辑 QObject 属性

Qt ListView 不显示 C++ 模型内容