QML中C++与ListModel交互摸索方案

最近有个毕设是用qml做界面,用C++写代码,遇到了需要用C++给QML中GridView的model赋值、更新等操作。

摸索1

一开始自然就想到使用ListModel,然后QMetaObject::invokeMethod来操作ListModel,代码为:(ListModel的objectName设为dataModel,id也设为dataModel)

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/view/qmls/main.qml")));
    QObject *topLevel=engine.rootObjects().value(0);
    QQuickWindow *window=qobject_cast<QQuickWindow*>(topLevel);

    QObject *model=window->findChild<QObject*>("dataModel");
    QVariant retValue;
    bool result=QMetaObject::invokeMethod(model,'get', Qt::DirectConnection,Q_RETURN_ARG(QVariant,retValue),Q_ARG(int,0));
    qDebug()<<result;
    window->showFullScreen();
    return app.exec();
}

以上代码就是调用ListModel自带的get方法获取到对应的值,并返回给retValue。理想很丰满,现实很骨感,result值为false,这就意味着方法调用失败,失败原因一般有两个:

  1. 方法名错误
  2. 参数错误

于是我觉得先将ListModel全部方法与入口参数,出口参数打印出来看看先

    const QMetaObject *mo=model->metaObject();
    for(int i=0;i<mo->methodCount();i++)
    {
        qDebug()<<mo->method(i).methodSignature()+"-outArg-"+mo->method(i).returnType();
    }

结果为:

"destroyed(QObject*)" -outArg- 43
"destroyed()" -outArg- 43
"objectNameChanged(QString)" -outArg- 43
"deleteLater()" -outArg- 43
"_q_reregisterTimers(void*)" -outArg- 43
"dataChanged(QModelIndex,QModelIndex,QVector<int>)" -outArg- 43
"dataChanged(QModelIndex,QModelIndex)" -outArg- 43
"headerDataChanged(Qt::Orientation,int,int)" -outArg- 43
"layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)" -outArg- 43
"layoutChanged(QList<QPersistentModelIndex>)" -outArg- 43
"layoutChanged()" -outArg- 43
"layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)" -outArg- 43
"layoutAboutToBeChanged(QList<QPersistentModelIndex>)" -outArg- 43
"layoutAboutToBeChanged()" -outArg- 43
"rowsAboutToBeInserted(QModelIndex,int,int)" -outArg- 43
"rowsInserted(QModelIndex,int,int)" -outArg- 43
"rowsAboutToBeRemoved(QModelIndex,int,int)" -outArg- 43
"rowsRemoved(QModelIndex,int,int)" -outArg- 43
"columnsAboutToBeInserted(QModelIndex,int,int)" -outArg- 43
"columnsInserted(QModelIndex,int,int)" -outArg- 43
"columnsAboutToBeRemoved(QModelIndex,int,int)" -outArg- 43
"columnsRemoved(QModelIndex,int,int)" -outArg- 43
"modelAboutToBeReset()" -outArg- 43
"modelReset()" -outArg- 43
"rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)" -outArg- 43
"rowsMoved(QModelIndex,int,int,QModelIndex,int)" -outArg- 43
"columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)" -outArg- 43
"columnsMoved(QModelIndex,int,int,QModelIndex,int)" -outArg- 43
"submit()" -outArg- 1
"revert()" -outArg- 43
"resetInternalData()" -outArg- 43
"countChanged()" -outArg- 43
"clear()" -outArg- 43
"remove(QQmlV4Function*)" -outArg- 43
"append(QQmlV4Function*)" -outArg- 43
"insert(QQmlV4Function*)" -outArg- 43
"get(int)" -outArg- 1052
"set(int,QQmlV4Handle)" -outArg- 43
"setProperty(int,QString,QVariant)" -outArg- 43
"move(int,int,int)" -outArg- 43
"sync()" -outArg- 43

returnType返回的是int值,其对应的表为:

ConstantValueDescription
QMetaType::Void43void
QMetaType::Bool1bool
QMetaType::Int2int
QMetaType::UInt3unsigned int
QMetaType::Double6double
QMetaType::QChar7QChar
QMetaType::QString10QString
QMetaType::QByteArray12QByteArray
QMetaType::VoidStar31void *
QMetaType::Long32long
QMetaType::LongLong4LongLong
QMetaType::Short33short
QMetaType::Char34char
QMetaType::ULong35unsigned long
QMetaType::ULongLong5ULongLong
QMetaType::UShort36unsigned short
QMetaType::SChar40signed char
QMetaType::UChar37unsigned char
QMetaType::Float38float
QMetaType::QObjectStar39QObject *
QMetaType::QVariant41QVariant
QMetaType::QCursor74QCursor
QMetaType::QDate14QDate
QMetaType::QSize21QSize
QMetaType::QTime15QTime
QMetaType::QVariantList9QVariantList
QMetaType::QPolygon71QPolygon
QMetaType::QPolygonF86QPolygonF
QMetaType::QColor67QColor
QMetaType::QSizeF22QSizeF
QMetaType::QRectF20QRectF
QMetaType::QLine23QLine
QMetaType::QTextLength77QTextLength
QMetaType::QStringList11QStringList
QMetaType::QVariantMap8QVariantMap
QMetaType::QVariantHash28QVariantHash
QMetaType::QIcon69QIcon
QMetaType::QPen76QPen
QMetaType::QLineF24QLineF
QMetaType::QTextFormat78QTextFormat
QMetaType::QRect19QRect
QMetaType::QPoint25QPoint
QMetaType::QUrl17QUrl
QMetaType::QRegExp27QRegExp
QMetaType::QRegularExpression44QRegularExpression
QMetaType::QDateTime16QDateTime
QMetaType::QPointF26QPointF
QMetaType::QPalette68QPalette
QMetaType::QFont64QFont
QMetaType::QBrush66QBrush
QMetaType::QRegion72QRegion
QMetaType::QBitArray13QBitArray
QMetaType::QImage70QImage
QMetaType::QKeySequence75QKeySequence
QMetaType::QSizePolicy121QSizePolicy
QMetaType::QPixmap65QPixmap
QMetaType::QLocale18QLocale
QMetaType::QBitmap73QBitmap
QMetaType::QMatrix79QMatrix
QMetaType::QTransform80QTransform
QMetaType::QMatrix4x481QMatrix4x4
QMetaType::QVector2D82QVector2D
QMetaType::QVector3D83QVector3D
QMetaType::QVector4D84QVector4D
QMetaType::QQuaternion85QQuaternion
QMetaType::QEasingCurve29QEasingCurve
QMetaType::QJsonValue45QJsonValue
QMetaType::QJsonObject46QJsonObject
QMetaType::QJsonArray47QJsonArray
QMetaType::QJsonDocument48QJsonDocument
QMetaType::QModelIndex42QModelIndex
QMetaType::QPersistentModelIndex50QPersistentModelIndex (since 5.5)
QMetaType::QUuid30QUuid
QMetaType::QByteArrayList49QByteArrayList
QMetaType::User1024Base value for user types
QMetaType::UnknownType0This is an invalid type id. It is returned from QMetaType for types that are not registered


竟然查不到值,只能去看源代码,最终查得是QQmlV4Function。
从上面可以知道是我的返回值参数写错了,对于其他方法我测试了是可以调用的。问题就是QQmlV4Function怎么用?他的头文件在哪?谷歌了好久无果放弃了。。。

一个折中的办法就是自己在ListMode里写一个js方法,在js里面调用get方法,c++再去调用自己那方法就可以实现返回值:

qml:

function getItem(index)
{
    return dataModel.get(index);
}

c++:
    bool result=QMetaObject::invokeMethod(model,'getItem', Qt::DirectConnection,Q_RETURN_ARG(QVariant,retValue),Q_ARG(QVariant,QVariant::fromValue(0)));

若是这样的话,ListModel的append方法也是要自己写,那不是很麻烦。。所以产生了能否使用一个类来代替ListModel。

摸索2

答案是有的,我采用的思路就是将一个C++类暴露给qml,使得在qml可以调用c++的方法。

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    //关键代码
    QQmlContext *content=engine.rootContext();
    DesignBLL *designBLL=new DesignBLL();
    content->setContextProperty("DesignBLL",designBLL);
    //
   engine.load(QUrl(QStringLiteral("qrc:/view/qmls/main.qml")));
    QObject *topLevel=engine.rootObjects().value(0);
    QQuickWindow *window=qobject_cast<QQuickWindow*>(topLevel);

    window->showFullScreen();
    return app.exec();
}

关键代码部分意思就是将DesignBLL 类实例化后直接暴露给QML,在QML里可以直接使用DesignBLL .方法()调用C++的方法。

DesignBLL.h代码为:

#ifndef DESIGNBLL_H
#define DESIGNBLL_H

#include <QObject>
#include <QQmlContext>
#include "DesignModel.h"
//类必须继承与QObject
class DesignBLL :public QObject{
    Q_OBJECT

public :
    DesignBLL();
    Q_INVOKABLE QList<QObject*> getModel();//必须加上Q_INVOKABLE才可以在QML被调用 
private:
    QList<QObject*> data;//作用等同与ListModel
};

#endif // DESIGNBLL_H

DesignBLL.cpp:

#include "DesignBLL.h"
//用作测试,在实例化时先添加一些测试数据
DesignBLL::DesignBLL(){
    for(int ii=0;ii<35;ii++){
        data.append(new DesignModel("#FFFFFF"));
    }
}

QList<QObject*> DesignBLL::getModel(){
    return data;
}

还要再定义一个DesignModel类,作用相当于ListElement

DesignModel.h

#ifndef DESIGNMODEL_H
#define DESIGNMODEL_H
#include<QObject>
#include<QVariant>
class DesignModel:public QObject{
    Q_OBJECT
    Q_PROPERTY(QString backColor READ backColor WRITE setBackColor NOTIFY backColorChanged)
  public:
    DesignModel(const QString &backColor,QObject *parent = 0);
    QString backColor() const;

    void setBackColor(const QString &backColor);

signals:
    void backColorChanged();
private:
    QString m_backColor;
};

#endif // DESIGNMODEL_H

主要就是定义1个元素backColor,之所以要加上Q_PROPERTY是因为使其可以在qml中被访问。

DesignModel.cpp:

#include "DesignModel.h"

DesignModel::DesignModel(const QString &backColor,QObject *parent):QObject(parent),m_backColor(backColor)
{

}

QString DesignModel::backColor() const{
    return m_backColor;
}

void DesignModel::setBackColor(const QString &backColor){
    m_backColor=backColor;
    emit backColorChanged();
}

这样一来在QML里调用getModel方法就可以了。

main.qml:

    GridView{
        id:designBox
        ...
        objectName: "designBox"
        Component.onCompleted: {
            designBox.model=DesignBLL.getModel();
        }
        delegate:Rectangle{
                height: 50
                width: 50
                color:model.modelData.backColor
            }
        }

运行结果正确,其他方法可以自己添加。这样一来

在QML里操作C++类数据:
designBox.model[index].backColor=”#FOFOFO”;


在C++里对数据进行更改界面也会同时更新

例如修改第二个的背景色

    DesignModel *tmp=dynamic_cast<DesignModel*>(data.at(2));
    tmp->setBackColor("#FF00FF");
或者
    QObject *obj=data[2];
    obj->setProperty("backColor",QVariant::fromValue(QString("#FF00FF")));

最终选用了第二种比较完美的方案。

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
QMLC++ 交互的过程一般分为以下几个步骤: 1. 定义 C++ 类并注册到 QML 你需要在 C++ 定义一个类,该类封装了你想要实现的功能。同时,你需要使用 `qmlRegisterType` 函数将该类注册到 QML ,以便在 QML 使用该类。 例如,你可以定义一个名为 `MyClass` 的类,并将其注册到 QML : ```cpp class MyClass : public QObject { Q_OBJECT public: Q_INVOKABLE int myFunction(int arg) { // 实现你的功能 } }; qmlRegisterType<MyClass>("com.example", 1, 0, "MyClass"); ``` 在上面的代码,`Q_INVOKABLE` 用于声明 `myFunction` 函数可从 QML 调用,`qmlRegisterType` 函数用于将 `MyClass` 类注册到 QML 。`"com.example"` 表示注册的命名空间,`1` 和 `0` 表示主版本号和次版本号,`"MyClass"` 是在 QML 使用的类名。 2. 在 QML 使用 C++ 类 在 QML 使用 C++ 类时,你需要使用 `import` 语句导入该类所在的命名空间。然后,你可以通过该命名空间来访问该类。例如: ```qml import com.example 1.0 MyClass { id: myClass } Button { onClicked: { var result = myClass.myFunction(42) // 处理返回值 } } ``` 在上面的代码,`import` 语句用于导入 `com.example` 命名空间,`MyClass` 用于创建一个 `MyClass` 实例,`id` 属性用于设置实例的标识符,`Button` 用于创建一个按钮,`onClicked` 事件处理程序调用了 `myFunction` 函数,并处理了它的返回值。 3. 在 C++ 访问 QML 的对象 如果你需要从 C++ 访问 QML 的对象,你可以使用 `QQuickItem` 类提供的 `findChild` 函数。例如: ```cpp QQuickItem *item = qmlEngine.rootObjects().value(0)->findChild<QQuickItem*>("myItem"); if (item) { // 处理 item 对象 } ``` 在上面的代码,`qmlEngine.rootObjects()` 函数返回 QML 引擎所有的根对象,`value(0)` 返回第一个根对象,`findChild` 函数用于查找名为 `"myItem"` 的子对象。 以上就是 QMLC++ 交互的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值