2017.5.8 更新:Record类要用指针,QObject 不能有拷贝函数。

我有一个C++中自定义的ReaderModel,继承自QAbstractListModel类,传递给了QML。

它的me成员是一个Reader指针,Reader有个成员是RecordModel。

通过reader获取的recordModel,在qml中类型是QVariant(RecordModel),我没法把它作为一个ListView的model。

要怎么让它绑定给view呢?

我尝试者把数据拷贝到一个直接传给qml的recordModel,但是当数据之后发生了变化时,视图就不会更新,除非再次拷贝,这样效率不可观。

通过艰难地google查找相关问题,我最后的解决方案是:

取消这个RecordModel成员,用QVariantList来储存所有record。

简单地说就是传递自定义类中的自定义结构体数组

作为解决方案的代码(如果不需要,完全可以不用ReaderModel,但是要用setContextProperty把reader变量传给qml):

record.h

#ifndef RECORD_H
#define RECORD_H
#include <QObject> class Record: public QObject
{
Q_OBJECT
Q_PROPERTY(QString bookId READ bookId WRITE setBookId NOTIFY bookIdChanged)
Q_PROPERTY(int state READ state WRITE setState NOTIFY stateChanged)
public:
Record(const QString &bookId="",int state=0):
bookId_(bookId),state_(state){} Record(const Record &r){
bookId_ = r.bookId_;
state_ = r.state_;
} QString bookId() const;
int state() const;
public slots:
void setBookId(const QString &);
void setState(int);
private:
QString bookId_;
int state_;
signals:
void bookIdChanged();
void stateChanged();
};
Q_DECLARE_METATYPE(Record*)//元类型注册
#endif // RECORD_H

reader.h

#ifndef READER_H
#define READER_H
#include <QObject>
#include <QVariantList>
class Reader: public QObject
{
Q_OBJECT
Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged)
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
Q_PROPERTY(QVariantList record READ record WRITE setRecord NOTIFY recordChanged)
public:
Reader(const QString &id = "",
const QString &password = "")
: id_(id),password_(password){} QString id() const; //id
QString password() const; //密码
QVariantList record() const; //记录 Q_INVOKABLE void doSomething()const; public slots:
void setId(const QString &);
void setPassword(const QString &);
void setRecord(const QVariantList &); private:
QString id_;
QString password_;
QVariantList record_;//借书记录 signals:
void idChanged();
void passwordChanged();
void recordChanged();
};
#endif // READER_H

readerModel.h

#ifndef READERMODEL_H
#define READERMODEL_H #include <QAbstractListModel>
#include <QJsonValueRef>
#include <QVariant>
#include "reader.h"
#include "record.h" class ReaderModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(Reader* me READ me WRITE setMe NOTIFY meChanged)
public:
enum ReaderRole {
IdRole = Qt::DisplayRole, //0
PasswordRole = Qt::UserRole,
RecordRole
};
Q_ENUM(ReaderRole) ReaderModel(QObject *parent = nullptr){Q_UNUSED(parent);} int rowCount(const QModelIndex & = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QHash<int, QByteArray> roleNames() const; Q_INVOKABLE QVariantMap get(int row) const;
Q_INVOKABLE void append(const QString &id,
const QString &password);
Q_INVOKABLE void set(int row, const QString &id,
const QString &password);
Q_INVOKABLE void remove(int row); Q_INVOKABLE Reader *me() const;//当前登录的用户对象指针
Q_INVOKABLE void setMe(Reader *r); private:
QList<Reader*> m_readers;
Reader *me_;
signals:
void meChanged();
}; #endif // READERMODEL_H

reader.cpp

#include "reader.h"
#include "record.h"
#include <QVariant>
QString Reader::id() const
{
return id_;
}
QString Reader::password() const
{
return password_;
}
QVariantList Reader::record() const
{
return record_;
}
void Reader::setId(const QString &value)
{
if (id_ == value)
return;
id_ = value;
emit idChanged();
}
void Reader::setPassword(const QString &value)
{
if (password_ == value)
return;
password_ = value;
emit passwordChanged();
}
void Reader::setRecord(const QVariantList &value)
{
if (record_ == value)
return;
record_ = value;
emit recordChanged();
}

record.cpp

#include "record.h"
QString Record::bookId() const
{
return bookId_;
}
int Record::state() const
{
return state_;
}
void Record::setBookId(const QString &value)
{
if(bookId_ == value)
return;
bookId_ = value;
emit bookIdChanged();
}
void Record::setState(int value)
{
if(state_ == value)
return;
state_ = value;
emit stateChanged();
}

readerModel.cpp

#include "readermodel.h"
#include "reader.h" int ReaderModel::rowCount(const QModelIndex & /*parent*/) const
{
return m_readers.count();
} QVariant ReaderModel::data(const QModelIndex &index, int role) const
{
if(index.row() < rowCount())
switch(role){
case IdRole: return m_readers.at(index.row())->id();
case PasswordRole: return m_readers.at(index.row())->password();
case RecordRole: return m_readers.at(index.row())->record();
default: return QVariant();
}
return QVariant();
} QHash<int, QByteArray> ReaderModel::roleNames() const
{
static const QHash<int, QByteArray> roles{
{IdRole, "id"},
{PasswordRole, "password"},
{RecordRole, "record"}
};
return roles;
} QVariantMap ReaderModel::get(int row) const
{
Reader *reader = m_readers.value(row);
return { {"id", reader->id()},
{"password", reader->password()},
{"record", reader->record()}};
} void ReaderModel::append(const QString &id, const QString &password)
{
int row = m_readers.count();
beginInsertRows(QModelIndex(), row, row);
Reader *r = new Reader(id, password, name, power, school, credit, money, unback);
m_readers.append(r);
endInsertRows();
} void ReaderModel::set(int row, const QString &id, const QString &password)
{
if (row < 0 || row >= m_readers.count())
return;
Reader *r = new Reader(id, password == ""? m_readers[row]->password() : password);
m_readers.replace(row, r);
dataChanged(index(row, 0), index(row, 0), { IdRole,PasswordRole});
} void ReaderModel::remove(int row)
{
if (row < 0 || row >= m_readers.count())
return; beginRemoveRows(QModelIndex(), row, row);
m_readers.removeAt(row);
endRemoveRows();
} Reader *ReaderModel::me() const
{
return me_;
} void ReaderModel::setMe(Reader *r)
{
me_ = r;
emit meChanged();
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QQmlContext>
#include "readermodel.h" int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv); //向qml注册类型
qmlRegisterType<ReaderModel>("Backend", 1, 0, "ReaderModel"); ReaderModel *readerModel = new ReaderModel();
...//写入数据
QQmlApplicationEngine *engine = new QQmlApplicationEngine(); //向qml传递变量
engine->rootContext()->setContextProperty("readerModel", readerModel);
engine->load(QUrl(QLatin1String("qrc:/main.qml"))); return app.exec();
}

mail.qml:

ListView {
visible: true
id: recordView
width: parent.width
height: parent.height
model: readerModel.me.record
delegate:Rectangle{
property var record: readerModel.me.record[index]
RowLayout{
spacing: 10
Label {
text: record.bookId
}
Label {
text: record.state
}
}
Component.onCompleted: {
console.log(readerModel.me.record)
console.log("\n",readerModel.me.record[index])
console.log("\n",readerModel.me.record[index].state)
}
}
}

参考:[SOLVED] Cascaded QVariantList exposed to QML causes Error: Cannot assign [undefined] to QString

【QML与C++混合编程】用QVariantList传递数组类型成员的更多相关文章

  1. QML与C++混合编程详解(转)

    原文转自:http://blog.csdn.net/ieearth/article/details/42243553 原文转自:https://www.cnblogs.com/findumars/p/ ...

  2. QML与C++混合编程详解

    1.QML与C++为什么要混合编程 QML与C++为什么要混合编程,简单来说,就是使用QML高效便捷地构建UI,而C++则用来实现业务逻辑和复杂算法,下面介绍了两者间交互的方法与技巧. 2.QML访问 ...

  3. 【Qt】Qt Quick 之 QML 与 C++ 混合编程详解

    Qt Quick 之 QML 与 C++ 混合编程详解 - CSDN博客   专栏:Qt Quick简明教程 - CSDN博客   .

  4. qml与c++混合编程

    QML 与 C++ 混合编程内容:1. QML 扩展2. C++ 与 QML 交互3. 开发时要尽量避免使用的 QML 元素4. demo 讲解5. QML 语法C++ 与 QML 的交互是通过注册 ...

  5. 由基于qml,c++的串口调试工具浅谈qml与c++混合编程

    最近在做一个基于sim900 的串口通信工具,基于qml和c++来实现. 首先,对于串口,qt有自带的QSerialPort,可以实现同步,和异步通信,qt creator也有自带的例子,本例子是从其 ...

  6. Qt Quick 之 QML 与 C++ 混合编程具体解释

    Qt Quick 技术的引入.使得你能够高速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的.也有非常多局限性,原来 Qt 的一些技术,比方低阶的网络编程如 QTcpSocke ...

  7. java matlab混合编程之返回值Struct类型

    java matlab混合编程的时候当返回值是Struct类型(matlab中的返回类型)如何来取得(java中)其值? 上网找,看到这个网页:http://www.mathworks.cn/cn/h ...

  8. 在Qt(C++)中与Python混合编程

    一.PythonQt库 在Qt(C++)中与Python混合编程,可以使用PythonQt库. 网站首页:http://pythonqt.sourceforge.net 下载页面:https://so ...

  9. C# 托管和非托管混合编程

    在非托管模块中实现你比较重要的算法,然后通过 CLR 的平台互操作,来使托管代码调用它,这样程序仍然能够正常工作,但对非托管的本地代码进行反编译,就很困难.   最直接的实现托管与非托管编程的方法就是 ...

随机推荐

  1. JS 原型与原型链

    图解: 一.普通对象 跟 函数对象 JavaScript 中,一切皆对象.但对象也有区别,分为 普通对象 跟 函数对象,Object 和 Function 是 JavaScript 自带的函数对象. ...

  2. oc之脚本

    进入Build Phases页面,点击加号选择“New Run Script Phases”创建Run Script 在这里添加Run Script, 1.每次编译运行版本号(bundleVersio ...

  3. centos 6.9:device eth0 does not seem to be present

    VMware上安装centos6.9,克隆一个新虚机,网卡不能桥接获得宿主机网络地址. https://blog.csdn.net/xiaobei4929/article/details/405152 ...

  4. 抓包工具之fiddler

    fiddler手机抓包的原理与抓pc上的web数据一样,都是把fiddler当作代理,网络请求走fiddler,fiddler从中拦截数据,由于fiddler充当中间人的角色,所以可以解密https ...

  5. SQL server 生成数据字典

    Set nocount on ), ) DECLARE Tbls CURSOR FOR ),isnull(g.[value],'-')) AS TABLE_COMMENT FROM INFORMATI ...

  6. javascript中的 return false和return true

    关于javascript中的 return false和return true,return 是javascript里函数返回值的关键字,一个函数内处理的结果可以使用return 返回,这样在调用函数 ...

  7. 使用css控制文字显示几行并且剩余部分隐藏(移动端和PC端同样适用)

    前言 有些需求需要我们控制一段文本最多显示几行,就像逛淘宝京东的评价楼层一样,有时可能还需要隐藏剩余部分,这样的需求我们怎么来解决呢? 解决办法 我们完全可以使用css来解决这一需求 1. 解决文本显 ...

  8. [转帖]十分钟快速理解DPI和PPI,不再傻傻分不清!

    十分钟快速理解DPI和PPI,不再傻傻分不清! https://baijiahao.baidu.com/s?id=1605834796518990333&wfr=spider&for= ...

  9. Notepad++的一个用法 转换为unix 格式的文件

    1. 跟昨天的linux 下面无法执行脚本的blog 一样 今天发现 notepad++ 有一个功能如下图: 双击 就能够选择文件的类型.. 转换为 unix 格式 就可以 在linux 下面执行了. ...

  10. MyBaits全局配置文件的各项标签2

    ▲typeHandlers 类型处理器,它架起数据库和JavaBean一一映射的桥梁,这里需要注意一下,java在JDK1.8之前,日期处理函数并不丰富,但在JDK1.8之后引入JSR-310标准,这 ...