C++传递数据到QML-setContextProperty以及结合listview使用

一、适用情况

在C++里将数据生成,然后将这个数据设置为qml的上下文属性,在qml里就能使用了

二、传递基础类型

1、main.cpp

QQuickWidget *m_widget = new QQuickWidget(this);
m_widget->setGeometry(0, 0, this->width(), this->height());
//关键代码
QString str = "zhuxy";
m_widget->rootContext()->setContextProperty("Zhuxy",str);
m_widget->setSource(QUrl("./main.qml"));
m_widget->show();

2、main.qml

import QtQuick 2.0
Rectangle
{
    id: mainWindow
    x: 30; y: 80; width: 1000; height: 800;
    Component.onCompleted: {
        console.log(Zhuxy);
    }
}

这里直接能用Zhuxy这个上下文属性

三、ListView+QStringList作为model

1、main.cpp

QStringList list;
list << "1" << "2";
m_widget->rootContext()->setContextProperty("Zhuxy",QVariant::fromValue(list));//不能是Test??
m_widget->setSource(QUrl("./test.qml"));
m_widget->show();

2、test.qml

import QtQuick 2.0ListView {
  width: 100; height: 100

  model: myModel
  delegate: Rectangle {
      height: 25
      width: 100
      Text { text: modelData }
  }
}

注意:经过测试这个上下文属性不能取名为Test(可能已经是内置上下文属性)

四、ListView+qml可访问的C++类

1、

mydata.h

#ifndef MYDATA_H
#define MYDATA_H

#include <QObject>

class Mydata : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
  public:
    Mydata(QObject *parent = nullptr);
    Mydata(const QString &value, const QString &name, QObject *parent = nullptr);
    QString value()const;
    void setValue(const QString &value);
    QString name()const;
    void setName(const QString& name);
  signals:
    void valueChanged();
    void nameChanged();
  private:
    QString m_value;
    QString m_name;
};

#endif // MYDATA_H

value和name就是qml可访问的值

mydata.cpp

#include "mydata.h"

Mydata::Mydata(QObject *parent) : QObject(parent)
{

}

Mydata::Mydata(const QString &value, const QString &name, QObject *parent)
    : QObject(parent),m_value(value),m_name(name)
{

}

QString Mydata::value() const
{
    return m_value;
}

void Mydata::setValue(const QString &value)
{
    if(this->m_value != value) {
        this->m_value = value;
        emit valueChanged();
    }

}

QString Mydata::name() const
{
    return m_name;
}

void Mydata::setName(const QString &name)
{
    if(this->m_name != name) {
        this->m_name = name;
        emit nameChanged();
    }
}

2、test.qml

import QtQuick 2.0

Rectangle
{
    id: mainWindow
    x: 30; y: 80; width: 1000; height: 800;
    ListView {
        anchors.fill: parent;
        model: ParaListModel;
        delegate: delegate_list
        spacing: 20;
        orientation: ListView.Horizontal

        //委托
        Component {
            id: delegate_list;
            Rectangle {
                id: rect;
                width: 80;
                height: width;
                color: "green";
                Text {
                    id: text1;
                    text: value;
                    horizontalAlignment: Text.AlignHCenter;
                    verticalAlignment: Text.AlignVCenter;
                    font.pixelSize: 16;
                    anchors.horizontalCenter: parent.horizontalCenter;
                    anchors.top: parent.top;
                    anchors.topMargin: 10;
                    color: "white";
                }
                Text {
                    id: text2;
                    text: name;
                    horizontalAlignment: Text.AlignHCenter;
                    verticalAlignment: Text.AlignVCenter;
                    font.pixelSize: 16;
                    anchors.horizontalCenter: parent.horizontalCenter;
                    anchors.bottom: parent.bottom;
                    anchors.bottomMargin: 10;
                    color: "white";
                }
            }
        }
    }

}

3、main.cpp

QList<QObject*> datalist;
datalist.append(new Mydata("item1", "red"));
datalist.append(new Mydata("item2", "green"));
datalist.append(new Mydata("item3", "blue"));
datalist.append(new Mydata("item4", "yellow"));
m_widget->rootContext()->setContextProperty("ParaListModel",QVariant::fromValue(datalist));

注意必须是QObject指针类型才能放进list等容器里,因为QObject的赋值构造函数是delete的

五、ListView+QAbstractListModel子类

注意当list的个数增加或减少是不支持更新的。

1、C++模型类ParaListModel.h

#ifndef PARALISTMODEL_H
#define PARALISTMODEL_H

#include <QAbstractListModel>

struct ParaModel
{
    ParaModel()
    {
        value = "";
        nodeName = "";
        nodeType = "";
        tableName = "";
        fieldName = "";
        module = "";
        location = "";
        rectRadius = -1;
    }
    //核心属性
    QString value;
    QString nodeName;
    QString nodeType;
    QString tableName;
    QString fieldName;
    //附加属性
    QString module;
    QString location;
    int rectRadius;
};

class ParaListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    ParaListModel(QObject* parent = 0);
    enum Roles//qml用来识别别名的规则
    {
        valueRole = Qt::UserRole + 1,
        nodeNameRole,
        nodeTypeRole,
        tableNameRole,
        fieldNameRole,
        moduleRole,
        locationRole,
        rectRadiusRole
    };
    void addModel(const ParaModel &deviceList);//C++设置值
    void update(int index, const ParaModel &paraModel);//C++更新
    int  rowCount(const QModelIndex &parent = QModelIndex()) const;//qml内部调用,不用多管直接重写即可
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;//qml内部调用,不用多管直接重写即可


protected:
    QHash<int, QByteArray> roleNames() const;//qml内部调用,不用多管直接重写即可

private:
    QList<ParaModel> m_data;
};

#endif // PARALISTMODEL_H

C++模型类ParaListModel.cpp

#include "paralistmodel.h"

ParaListModel::ParaListModel(QObject *parent)
    : QAbstractListModel(parent)
{

}

void ParaListModel::addModel(const ParaModel &paraModel)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_data << paraModel;
    endInsertRows();
}



int ParaListModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_data.count();
}

QVariant ParaListModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= m_data.count())
        return QVariant();

    const ParaModel &paraModel = m_data[index.row()];
    switch (role)
    {
    case valueRole:
        return paraModel.value;
        break;
    case nodeNameRole:
        return paraModel.nodeName;
        break;
    case nodeTypeRole:
        return paraModel.nodeType;
        break;
    case tableNameRole:
        return paraModel.tableName;
        break;
    case fieldNameRole:
        return paraModel.fieldName;
        break;
    case moduleRole:
        return paraModel.module;
        break;
    case locationRole:
        return paraModel.location;
        break;
    case rectRadiusRole:
        return paraModel.rectRadius;
        break;
    default:
        break;
    }
    return QVariant();
}

void ParaListModel::update(int index, const ParaModel &paraModel)
{
    if (index < 0 || index >= m_data.count())
        return;
    ParaModel &srcModel = m_data[index];
    if(paraModel.value != "")
    {
        srcModel.value = paraModel.value;
    }
    if(paraModel.nodeName != "")
    {
        srcModel.nodeName = paraModel.nodeName;
    }
    if(paraModel.nodeType != "")
    {
        srcModel.nodeType = paraModel.nodeType;
    }
    if(paraModel.tableName != "")
    {
        srcModel.tableName = paraModel.tableName;
    }
    if(paraModel.fieldName != "")
    {
        srcModel.fieldName = paraModel.fieldName;
    }
    if(paraModel.module != "")
    {
        srcModel.module = paraModel.module;
    }
    if(paraModel.location != "")
    {
        srcModel.location = paraModel.location;
    }
    if(paraModel.rectRadius != -1)
    {
        srcModel.rectRadius = paraModel.rectRadius;
    }
}

//qml通过这里的QByteArray来访问数据
QHash<int, QByteArray> ParaListModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[valueRole] = "value";
    roles[nodeNameRole] = "nodeName";
    roles[nodeTypeRole] = "nodeType";
    roles[tableNameRole] = "tableName";
    roles[fieldNameRole] = "fieldName";
    roles[moduleRole] = "module";
    roles[locationRole] = "location";
    roles[rectRadiusRole] = "rectRadius";
    return roles;
}

qml通过3个重写的函数来获取每个model的值:

首先通过rouCount获取model个数;

再通过roleNames获取每个变量名和其role的值;

最后根据role的值访问data函数,获取到真实值

2、test.qml

import QtQuick 2.0

Rectangle {
    width: 800;
    height: 300;
    color: "#222648";//背景色
    property int rect_width: 80;//参数宽度
    property color text_color: "white";//字体颜色
    ListView {
        width: parent.width;
        height: rect_width;
        anchors.centerIn: parent;
        model: ParaListModel;
        delegate: delegate_list
        spacing: 20;
        orientation: ListView.Horizontal
    }
    //委托
    Component {
        id: delegate_list;
        Rectangle {
            id: rect;
            width: rect_width;
            height: width;
            radius: rectRadius;
            color: bkColor;
            property string q_tableName: tableName;//其他不用显示的属性
            property string q_fieldName: fieldName;
            Text {
                id: text1;
                text: value;
                horizontalAlignment: Text.AlignHCenter;
                verticalAlignment: Text.AlignVCenter;
                font.pixelSize: 16;
                anchors.horizontalCenter: parent.horizontalCenter;
                anchors.top: parent.top;
                anchors.topMargin: 10;
                color: text_color;
            }
            Text {
                id: text2;
                text: nodeName;
                horizontalAlignment: Text.AlignHCenter;
                verticalAlignment: Text.AlignVCenter;
                font.pixelSize: 16;
                anchors.horizontalCenter: parent.horizontalCenter;
                anchors.bottom: parent.bottom;
                anchors.bottomMargin: 10;
                color: text_color;
            }
            MouseArea {
                anchors.fill: parent;
                hoverEnabled: true;
                cursorShape: (containsMouse? (pressed? Qt.ClosedHandCursor: Qt.OpenHandCursor): Qt.ArrowCursor);//设置鼠标样式
                onDoubleClicked: {
                    console.log(q_tableName,q_fieldName);
                }
            }
        }
    }

}

3、main.cpp

m_widget = new QQuickWidget(this);
m_widget->setGeometry(0, 0, this->width(), this->height());
//关键代码
ParaListModel modelList;
for(int i=0;i<5;i++)
{
    ParaModel model;
    model.value = "value:"+QString::number(i);
    model.nodeName = "nodeName:"+QString::number(i);
    model.nodeType = "nodeType:"+QString::number(i);
    model.tableName = "tableName:"+QString::number(i);
    model.fieldName = "fieldName:"+QString::number(i);
    model.rectRadius = 40;
    modelList.addModel(model);
}
m_widget->rootContext()->setContextProperty("ParaListModel",&modelList);

//测试实时更新qml中的值
ParaModel model;
model.value = "new";
model.nodeName = "new";
model.rectRadius = 10;
modelList.update(4,model);

C++传递数据到QML-setContextProperty以及结合listview使用

六、C++修改值QML自动更新

1、数据类

data.h

#ifndef DATA_H
#define DATA_H

#include <QObject>

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString count READ count WRITE setCount NOTIFY countChanged)
public:
    Data(QObject *parent = nullptr);
    Data(const QString& count,QObject* parent = nullptr);

    QString count() const;
    void setCount(const QString& count);


signals:
    void countChanged();

public slots:


private:
    QString m_count = "0";
};

#endif // DATA_H

data.cpp

#include "data.h"

Data::Data(QObject *parent) : QObject(parent)
{

}

Data::Data(const QString &count, QObject *parent)
    : m_count(count), QObject(parent)
{

}

QString Data::count() const
{
    return m_count;
}

void Data::setCount(const QString &count)
{
    if(m_count != count)
    {
        m_count = count;
        emit countChanged();
    }
}

2、在mainwindow里拖一个quickwidget,然后装载qml文件,

核心代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "data.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
    Data data;
    volatile int __count = 0;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQuickWidget>
#include <QQmlContext>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QUrl source("qrc:/qml/qml/Test.qml");
    ui->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView );
    ui->quickWidget->setSource(source);
    ui->quickWidget->setClearColor(QColor(Qt::transparent));


    data.setCount("0");
    ui->quickWidget->rootContext()->setContextProperty("Data",&data);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    __count++;
    data.setCount(QString::number(__count));
}

void MainWindow::on_pushButton_2_clicked()
{
     __count--;
     data.setCount(QString::number(__count));
}

界面:

C++传递数据到QML-setContextProperty以及结合listview使用

3、qml

import QtQuick 2.7

Item {
    Text {
        id: txt;
        color: "red";
        text: Data.count;
        anchors.centerIn: parent;
        font.pixelSize: 30;
    }
}

作用就是在qml显示一个数字,点击+就加1,点击-就减1

效果:

C++传递数据到QML-setContextProperty以及结合listview使用

ps:

1、程序运行会打印xx没有被定义,这是正常的现象,这个Data就是setContextProperty的参数

C++传递数据到QML-setContextProperty以及结合listview使用

2、注意如果想要实现动态绑定,就必须要继承QObject,并且让属性被Q_PROPERTY标记【实现其读写、变化函数】

所以定义一个int、QString等类型,qml是无法与其进行动态绑定的,因为int和QString都没有实现这个操作。

3、在qml里获取C++的变量,就会对应调用C++的获取xxx函数;在qml里设置这个变量,就会对应调用C++里的setXXX函数

C++传递数据到QML-setContextProperty以及结合listview使用

原文链接: https://www.cnblogs.com/judes/p/13460913.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/201236

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午8:43
下一篇 2023年2月12日 下午8:43

相关推荐