首先,我是 Qt6 和 QML 的新手,所以也许我遗漏了一些明显的东西。
我正在尝试从
QObject
属性将 C++ 模型链接到 QML 中的 ListView。List<QObject*>
作为静态模型。
但是,在该示例中,
QList<QObject*>
直接传递给 QQuickView
。QObject
的属性访问对象列表,我已经可以在 QML 中访问。这是我想要实现的目标的最小工作示例:
后端.h
#ifndef BACKEND_H
#define BACKEND_H
#include <QObject>
// Contains the data I want to display for each element
class Item : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER m_name NOTIFY onNameChanged)
public:
Item(QString name, QObject *parent = nullptr)
: QObject{parent}, m_name(name)
{}
signals:
void onNameChanged();
private:
QString m_name {"NULL"};
};
// This class contains the model I want to display.
// The data will be loaded before loading the QML file.
// It can be switched between a mockup and a real backend depending on the context.
class Backend : public QObject
{
Q_OBJECT
Q_PROPERTY(QString header MEMBER m_header NOTIFY onHeaderChanged)
Q_PROPERTY(QList<QObject*> model MEMBER m_model NOTIFY onModelChanged)
public:
explicit Backend(QObject *parent = nullptr)
: QObject{parent}
{
m_header = "Cpp Backend";
m_model.append(new Item {"Cpp"});
m_model.append(new Item {"backend"});
m_model.append(new Item {"is"});
m_model.append(new Item {"great!"});
}
virtual ~Backend() override
{
for (QObject* item : m_model)
delete item;
}
signals:
void onHeaderChanged();
void onModelChanged();
private:
QString m_header;
QList<QObject*> m_model;
};
#endif // BACKEND_H
主.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQMLContext>
#include "backend.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// Exposing the backend to QML with the name "cppBackend"
Backend backend;
engine.rootContext()->setContextProperty("cppBackend", &backend);
const QUrl url(u"qrc:/TestBackend/Main.qml"_qs);
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
主要.qml
import QtQuick
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
ListModel {
id: mockupList
ListElement { name: "Hello" }
ListElement { name: "World!" }
ListElement { name: "How" }
ListElement { name: "are" }
ListElement { name: "you?" }
}
ListView {
id: listView
anchors.fill: parent
anchors.margins: 20
spacing: 10
orientation: ListView.Vertical
//model: mockupList // this works as expected
model: cppBackend.model // this doesn't show anything in the listview
delegate: Item {
id: myItem
required property string name
width: label.width
height: label.height
Text {
id: label
text: myItem.name
font.pointSize: 24
}
}
header: Text {
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pointSize: 48
font.bold: true
text: cppBackend.header // This works as expected
}
}
}
当我使用 te
mockupList
而不是 C++ 后端时,项目会按预期显示。cppBackend
时,我收到此警告:
qrc:/TestBackend/Main.qml:30:13: Required property name was not initialized qrc:/TestBackend/Main.qml: 30
似乎属性
cppBackend.model
已被访问,但内部的项目不提供对其属性的访问,因为似乎应该在Qt文档中完成...
直接从 QML 公开模型效果很好,尽管通过 Q_PROPERTY 访问模型似乎由于某种原因失败。我自己不明白其中的区别,但这是我如何让它发挥作用的:
首先创建一个访问器来获取模型:
class Backend : public QObject
{
Q_OBJECT
public:
...
QList<QObject *> model() { return m_model; }
};
然后将该模型公开给 QML:
Backend backend;
engine.rootContext()->setContextProperty("cppBackendModel", QVariant::fromValue(backend.model()));
最后从 QML 访问该模型。
ListView {
id: listView
model: cppBackendModel
delegate: Item {
id: myItem
required property string name
...
}
}