• 【QML与C++混合编程】用QVariantList传递数组类型成员


    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
       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("
    ",readerModel.me.record[index])
            console.log("
    ",readerModel.me.record[index].state)
          }
      }
    }
    

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

  • 相关阅读:
    SPOJ
    hdu1298(字典树)
    hdu1247(字典树)
    hdu1075(字典树)
    Redisson教程
    Redisson官方文档
    Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数
    防止XSS脚本注入-前端vue、后端springboot
    在Intellij IDEA中使用Debug
    使用Hibernate-Validator优雅的校验参数
  • 原文地址:https://www.cnblogs.com/flipped/p/6788121.html
Copyright © 2020-2023  润新知