美文网首页Qt QML 杂记
QML 中使用 QAbstractListModel 作为 Li

QML 中使用 QAbstractListModel 作为 Li

作者: 赵者也 | 来源:发表于2017-11-14 17:46 被阅读693次

    本文对应的源码地址:
    https://github.com/imtoby/CppModelForQMLExample

    程序运行效果:

    运行效果

    我们需要注意的是我们在使用 QAbstractListModel 时至少要实现的方法:

    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    virtual QHash<int, QByteArray> roleNames() const;
    

    我们定义一个继承自 QAbstractListModel 的类 ObjectModel 用于管理 QObject 对象列表,并将其作为 ListView 的 model 传给 QML 端使用。

    下面是其头文件的内容:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: ObjectModel.h
     ***************************************************************************/
    #ifndef OBJECTMODEL_H_2DBDF593_DAA2_5084_8BE0_A727A0C68256
    #define OBJECTMODEL_H_2DBDF593_DAA2_5084_8BE0_A727A0C68256
    
    #include <QAbstractListModel>
    
    class ObjectModelPrivate;
    
    class ObjectModel : public QAbstractListModel
    {
        Q_OBJECT
    public:
        explicit ObjectModel(QObject *parent = 0);
        ~ObjectModel();
    
        int rowCount(const QModelIndex &parent) const;
        int columnCount(const QModelIndex &parent) const;
        QVariant data(const QModelIndex &index, int role) const;
        bool setData(const QModelIndex &index, const QVariant &value, int role);
        virtual QHash<int, QByteArray> roleNames() const;
    
        void insert(int index, QObject* object);
        void append(QObject* object);
        void push_front(QObject* object);
        void push_back(QObject* object);
    
        void replace(int index, QObject* object);
        void set(QObjectList * objectList);
    
        void remove(QObject* object);
        void remove(int index);
        void clear();
    
        QObject * get(int index);
        QObjectList* getAll();
    
    private:
        QScopedPointer<ObjectModelPrivate> d_ptr;
        Q_DECLARE_PRIVATE(ObjectModel)
    };
    
    #endif // OBJECTMODEL_H_2DBDF593_DAA2_5084_8BE0_A727A0C68256
    

    然后是实现文件:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: ObjectModel.cpp
     ***************************************************************************/
    #include "ObjectModel.h"
    #include <QMutex>
    
    #include "Config.h"
    
    namespace {
    
    enum {
        ObjectModelRole = Qt::UserRole + 1
    };
    
    }
    
    class ObjectModelPrivate
    {
    public:
        ObjectModelPrivate(ObjectModel * parent)
            : q_ptr(parent)
            , mutex(NULL)
        {
        }
    
        void init();
        void uninit();
    
    private:
        ObjectModel * const q_ptr;
        Q_DECLARE_PUBLIC(ObjectModel)
    
        QHash<int, QByteArray> rolesNames;
        QObjectList objectList;
        QMutex *mutex;
    };
    
    ObjectModel::ObjectModel(QObject *parent) :
        QAbstractListModel(parent),
        d_ptr(new ObjectModelPrivate(this))
    {
        Q_D(ObjectModel);
        d->init();
        d->rolesNames[ObjectModelRole] = "objectModelRole";
    }
    
    ObjectModel::~ObjectModel()
    {
        Q_D(ObjectModel);
        d->uninit();
    }
    
    int ObjectModel::rowCount(const QModelIndex &parent) const
    {
        C_D(ObjectModel);
        Q_UNUSED(parent);
        return d->objectList.size();
    }
    
    int ObjectModel::columnCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return 1;
    }
    
    QVariant ObjectModel::data(const QModelIndex &index, int role) const
    {
        C_D(ObjectModel);
        if (index.row() >= 0 && index.row() < d->objectList.size() ) {
            if (role == ObjectModelRole) {
                QObject *object = d->objectList.at(index.row());
                return QVariant::fromValue(object);
            }
        }
        return QVariant(0);
    }
    
    bool ObjectModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        Q_D(ObjectModel);
        if (index.row() >= 0 && index.row() < d->objectList.size() ) {
            if (role == ObjectModelRole) {
                d->mutex->lock();
                d->objectList.replace(index.row(), value.value<QObject *>());
                d->mutex->unlock();
                return true;
            }
        }
        return false;
    }
    
    QHash<int, QByteArray> ObjectModel::roleNames() const
    {
        C_D(ObjectModel);
        return d->rolesNames;
    }
    
    void ObjectModel::insert(int index, QObject *object)
    {
        Q_D(ObjectModel);
        if (index >= 0  && index <= d->objectList.size()) {
            d->mutex->lock();
            beginInsertRows(QModelIndex(), index, index);
            d->objectList.insert(index, object);
            endInsertRows();
            d->mutex->unlock();
        }
    }
    
    void ObjectModel::append(QObject *object)
    {
        Q_D(ObjectModel);
        insert(d->objectList.size(), object);
    }
    
    void ObjectModel::push_front(QObject *object)
    {
        insert(0, object);
    }
    
    void ObjectModel::push_back(QObject *object)
    {
        append(object);
    }
    
    void ObjectModel::replace(int index, QObject *object)
    {
        Q_D(ObjectModel);
        if (index >= 0  && index < d->objectList.size()) {
            d->mutex->lock();
            d->objectList.replace(index, object);
            d->mutex->unlock();
            emit dataChanged(createIndex(index, 0), createIndex(index, 0));
        }
    }
    
    void ObjectModel::set(QObjectList *objectList)
    {
        Q_D(ObjectModel);
        d->mutex->lock();
        beginResetModel();
        d->objectList = *objectList;
        endResetModel();
        d->mutex->unlock();
    }
    
    void ObjectModel::remove(QObject *object)
    {
        Q_D(ObjectModel);
        d->mutex->lock();
        const int index = d->objectList.indexOf(object);
        if (index >= 0) {
            beginRemoveRows(QModelIndex(), index, index);
            d->objectList.removeAt(index);
            endRemoveRows();
        }
        d->mutex->unlock();
    }
    
    void ObjectModel::remove(int index)
    {
        Q_D(ObjectModel);
        if (index >= 0 && index < d->objectList.size()) {
            d->mutex->lock();
            beginRemoveRows(QModelIndex(), index, index);
            QObject* object = d->objectList.at(index);
            d->objectList.removeAt(index);
            object->deleteLater();
            endRemoveRows();
            d->mutex->unlock();
        }
    }
    
    void ObjectModel::clear()
    {
        Q_D(ObjectModel);
        d->mutex->lock();
        beginResetModel();
        qDeleteAll(d->objectList.begin(), d->objectList.end());
        d->objectList.clear();
        endResetModel();
        d->mutex->unlock();
    }
    
    QObject *ObjectModel::get(int index)
    {
        Q_D(ObjectModel);
        if (index >= 0 && index < d->objectList.size()) {
            d->mutex->lock();
            QObject * object = d->objectList.at(index);
            d->mutex->unlock();
            return object;
        }
        return NULL;
    }
    
    QObjectList *ObjectModel::getAll()
    {
        Q_D(ObjectModel);
        d->mutex->lock();
        QObjectList * objectList = &(d->objectList);
        d->mutex->unlock();
        return objectList;
    }
    
    
    void ObjectModelPrivate::init()
    {
        rolesNames.clear();
        objectList.clear();
        if (mutex == NULL) {
            mutex = new QMutex(QMutex::Recursive);
        }
    }
    
    void ObjectModelPrivate::uninit()
    {
        qDeleteAll(objectList.begin(), objectList.end());
        objectList.clear();
        rolesNames.clear();
        if (mutex) {
            delete mutex;
            mutex = NULL;
        }
    }
    

    这里定义一个继承自 QObject 的子类 TestItem,用于作为实际的数据结构存储类。
    其头文件如下:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: TestItem.h
     ***************************************************************************/
    #ifndef TESTITEM_H_B3E135CE_37B2_5BA7_B57A_AD850A413E91
    #define TESTITEM_H_B3E135CE_37B2_5BA7_B57A_AD850A413E91
    
    #include <QObject>
    
    class TestItemPrivate;
    
    class TestItem : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    public:
        explicit TestItem(QObject *parent = 0);
        ~TestItem();
    
        TestItem(const TestItem &other, QObject *parent = 0);
        TestItem& operator=(const TestItem &other);
    
        QString name() const;
        void setName(const QString& name);
    
    signals:
        void nameChanged();
    
    private:
        QScopedPointer<TestItemPrivate> d_ptr;
        Q_DECLARE_PRIVATE(TestItem)
    };
    
    #endif // TESTITEM_H_B3E135CE_37B2_5BA7_B57A_AD850A413E91
    

    实现文件如下:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: TestItem.cpp
     ***************************************************************************/
    #include "TestItem.h"
    
    #include "Config.h"
    
    class TestItemPrivate
    {
    public:
        TestItemPrivate(TestItem *parent)
            : q_ptr(parent)
            , name("test")
        {}
    
    private:
        TestItem * const q_ptr;
        Q_DECLARE_PUBLIC(TestItem)
    
        QString name;
    };
    
    TestItem::TestItem(QObject *parent) :
        QObject(parent) ,
        d_ptr(new TestItemPrivate(this))
    {
    }
    
    TestItem::~TestItem()
    {
    }
    
    TestItem::TestItem(const TestItem &other, QObject *parent) :
        QObject(parent) ,
        d_ptr(new TestItemPrivate(this))
    {
        d_ptr.swap(const_cast< QScopedPointer<TestItemPrivate>&>(other.d_ptr));
    }
    
    TestItem &TestItem::operator=(const TestItem &other)
    {
        d_ptr.swap(const_cast< QScopedPointer<TestItemPrivate>&>(other.d_ptr));
        return *this;
    }
    
    QString TestItem::name() const
    {
        C_D(TestItem);
        return d->name;
    }
    
    void TestItem::setName(const QString& name)
    {
        Q_D(TestItem);
        if (name != d->name) {
            d->name = name;
            emit nameChanged();
        }
    }
    

    接下来我们定义一个数据管理类 ModelManager,其头文件如下:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: ModelManager.h
     ***************************************************************************/
    #ifndef MODELMANAGER_H_0E42B205_5B88_5E39_84B8_6A36CED83E8A
    #define MODELMANAGER_H_0E42B205_5B88_5E39_84B8_6A36CED83E8A
    
    #include <QObject>
    
    #include "ObjectModel.h"
    
    class ModelManagerPrivate;
    
    class ModelManager : public QObject
    {
        Q_OBJECT
    public:
        explicit ModelManager(QObject *parent = 0);
        ~ModelManager();
    
        Q_INVOKABLE void initData();
        Q_INVOKABLE ObjectModel* objectModel();
        Q_INVOKABLE void testInsert();
    
    private:
        QScopedPointer<ModelManagerPrivate> d_ptr;
        Q_DECLARE_PRIVATE(ModelManager)
    };
    
    #endif // MODELMANAGER_H_0E42B205_5B88_5E39_84B8_6A36CED83E8A
    

    实现文件如下:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: ModelManager.cpp
     ***************************************************************************/
    #include "ModelManager.h"
    #include <QThread>
    #include <QDateTime>
    
    #include "TestItem.h"
    
    class ModelManagerPrivate
    {
    public:
        ModelManagerPrivate(ModelManager *parent)
            : q_ptr(parent)
            , objectModel(NULL)
        {
        }
    
        void init();
        void uninit();
    
    private:
        ModelManager * const q_ptr;
        Q_DECLARE_PUBLIC(ModelManager)
    
        ObjectModel* objectModel;
        QThread workerThread;
    };
    
    ModelManager::ModelManager(QObject *parent) :
        QObject(parent),
        d_ptr(new ModelManagerPrivate(this))
    {
        Q_D(ModelManager);
        d->init();
    }
    
    ModelManager::~ModelManager()
    {
        Q_D(ModelManager);
        d->uninit();
    }
    
    void ModelManager::initData()
    {
        Q_D(ModelManager);
        QObjectList testItemList;
        for (int i=0; i<5; ++i) {
            TestItem* newTestItem = new TestItem(this);
            testItemList.append(newTestItem);
        }
        d->objectModel->set(&testItemList);
    }
    
    ObjectModel *ModelManager::objectModel()
    {
        Q_D(ModelManager);
        return d->objectModel;
    }
    
    void ModelManager::testInsert()
    {
        Q_D(ModelManager);
        TestItem* newTestItem = new TestItem(this);
        newTestItem->setName(QString::number(QDateTime::currentMSecsSinceEpoch()));
        d->objectModel->append(newTestItem);
    }
    
    void ModelManagerPrivate::init()
    {
        Q_Q(ModelManager);
        if (objectModel == NULL) {
            objectModel = new ObjectModel(q);
        }
    }
    
    void ModelManagerPrivate::uninit()
    {
        if (objectModel) {
            objectModel->deleteLater();
            objectModel = NULL;
        }
    }
    

    接下来是用于测试的 main.cpp 文件的内容:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: main.cpp
     ***************************************************************************/
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QQmlEngine>
    #include <QQuickItem>
    
    #include "ModelManager.h"
    #include "ObjectModel.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        // 向 QML 域注册 ObjectModel 类
        qmlRegisterUncreatableType<ObjectModel, 1>("com.test.model", 1, 0,
                                                   "ObjectModel",
                                                   "Cannot create ObjectModel");
    
        ModelManager* modelMgr = new ModelManager(&app);
        engine.rootContext()->setContextProperty("modelMgr", modelMgr);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        // 初始化数据
        modelMgr->initData();
    
        int r = app.exec();
    
        if (modelMgr) {
            modelMgr->deleteLater();
            modelMgr = NULL;
        }
    
        return r;
    }
    

    至于 QML 文件就相对很简单了:

    /***************************************************************************
        Copyright (C) 2017 by ZhaoDongshuang
        Author: ZhaoDongshuang
        Email: imtoby@126.com
        Date: 2017/11/07
        File: main.qml
     ***************************************************************************/
    import QtQuick 2.3
    import QtQuick.Window 2.2
    import "qml/dialog"
    
    Window {
        id: rootWindow
        visible: true
        width: 240
        height: 360
    
        ListView {
            anchors.fill: parent
    
            model: modelMgr.objectModel()
    
            delegate: Text {
                width: rootWindow.width
                height: 40
                text: model.modelData.name + index
            }
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: {
                modelMgr.testInsert()
            }
        }
    }
    

    相关文章

      网友评论

      • 3f9b7dcb0845:太感谢了,为了达到同样效果,我折腾QQmlListProperty一晚上...
        赵者也:不用客气😆

      本文标题:QML 中使用 QAbstractListModel 作为 Li

      本文链接:https://www.haomeiwen.com/subject/cvpfvxtx.html