为 QML ListView 实现 QAbstractListModel 子类?
Posted
技术标签:
【中文标题】为 QML ListView 实现 QAbstractListModel 子类?【英文标题】:Implementing a QAbstractListModel subclass for QML ListView? 【发布时间】:2020-12-23 03:53:20 【问题描述】:如何实现QAbstractListModel
的data
函数,使其返回具有从QML ListView
的委托可见的属性的东西?
对于项目类型,我尝试实现具有Q_PROPERTY
s 的QObject
子类,但QAbstractListModel::data
返回QVariant
,并且QObject*
无法转换为QVariant
?
如何创建一个 QVariant
,它的命名属性对 QML 可见?
class MyListItem : public QObject
Q_OBJECT
Q_PROPERTY(type name READ name WRITE set_name NOTIFY nameChanged)
/*...*/
public:
MyListItem(QObject* parent, const QString& name) : QObject(parent)
set_name(name);
;
class MyList : public QAbstractListModel
public:
MyList(QObject* parent);
Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override;
Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVector<MyListItem*> items;
;
Q_INVOKABLE int MyList::rowCount(const QModelIndex &) const
return items.size();
Q_INVOKABLE QVariant MyList::data(const QModelIndex &index, int) const
MyListItem* item = items[index.row()];
return item; // <--- ERROR
获取:
In member function ‘virtual QVariant MyList::data(const QModelIndex&, int) const’: error: use of deleted function ‘QVariant::QVariant(void*)’ 18 | return item; | ^~~~
【问题讨论】:
请提供一个minimal reproducible example,如果它可以包含指向QObject的指针,请提供一个QVariant,所以我认为问题是另一个 @eyllanesc:查看更新。无法将QObject*
转换为 QVariant
【参考方案1】:
如果你想将一个 QObject 封装在一个 QVariant 中,那么你必须使用QVariant::fromValue
:
return QVariant::fromValue(item);
MWE:
main.cpp
#include <QAbstractListModel>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
class MyListItem : public QObject
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE set_name NOTIFY nameChanged)
public:
MyListItem(const QString& name, QObject* parent=nullptr) : QObject(parent), m_name(name)
QString name() const
return m_name;
public slots:
void set_name(QString name)
if (m_name == name)
return;
m_name = name;
emit nameChanged(m_name);
signals:
void nameChanged(QString name);
private:
QString m_name;
;
class MyList : public QAbstractListModel
public:
enum MyListRoles
ItemRole = Qt::UserRole + 1
;
MyList(QObject* parent=nullptr): QAbstractListModel(parent)
~MyList()
qDeleteAll(items);
items.clear();
void append(MyListItem *item)
beginInsertRows(QModelIndex(), rowCount(), rowCount());
items.append(item);
endInsertRows();
int rowCount(const QModelIndex &parent=QModelIndex()) const override
if(parent.isValid())
return 0;
return items.count();
QVariant data(const QModelIndex &index, int role) const override
if(!index.isValid())
return ;
if(index.row() <0 || index.row() >= rowCount())
return ;
if(role == ItemRole)
return QVariant::fromValue(items[index.row()]);
return ;
QHash<int, QByteArray> roleNames() const override
return ItemRole, "item";
private:
QVector<MyListItem*> items;
;
#include "main.moc"
int main(int argc, char *argv[])
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
MyList model;
model.append(new MyListItem("foo1"));
model.append(new MyListItem("foo2"));
model.append(new MyListItem("foo3"));
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("mylist", &model);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl)
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
, Qt::QueuedConnection);
engine.load(url);
return app.exec();
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
ListView
anchors.fill: parent
model: mylist
delegate: Text
text: model.item.name
【讨论】:
谢谢,这很有帮助。此外,我缺少的部分是角色的概念。在实现roleNames
并观察role
的QAbstractListModel::data
参数之后,我现在可以正常工作了。 (我认为 ListView 委托中的引用是 QObject 的属性——事实并非如此——它们使用的是角色机制)以上是关于为 QML ListView 实现 QAbstractListModel 子类?的主要内容,如果未能解决你的问题,请参考以下文章
Qml自定义组件 - ListView下拉刷新 - PullToRefreshHandler
qml----Model/View入门ListView动画效果