【问题标题】:Implementing a QAbstractListModel subclass for QML ListView?为 QML ListView 实现 QAbstractListModel 子类?
【发布时间】:2020-12-23 03:53:20
【问题描述】:

如何实现QAbstractListModeldata 函数,使其返回具有从QML ListView 的委托可见的属性的东西?

对于项目类型,我尝试实现具有Q_PROPERTYs 的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

标签: c++ qt qml


【解决方案1】:

如果你想将一个 QObject 封装在一个 QVariant 中,那么你必须使用QVariant::fromValue:

return QVariant::fromValue(item);

MWE:

ma​​in.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();
}

ma​​in.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 并观察roleQAbstractListModel::data 参数之后,我现在可以正常工作了。 (我认为 ListView 委托中的引用是 QObject 的属性——事实并非如此——它们使用的是角色机制)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-07
  • 2021-08-03
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2014-05-18
相关资源
最近更新 更多