本文对应的源码地址:
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()
}
}
}
网友评论