Qml学习笔记:cpp与qml的交互调用方式

14 篇文章 0 订阅

如何用在cpp中调用qml的方法

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5 as Controls
Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    //Qml通信cpp
    Controls.Label
    {
        objectName: 'labelcpp'
        text: 'Qml && cpp'
        font.pointSize: 38

        //cpp调用这个函数
        function getText()
        {
            return text
        }
        //加参数后
        function getText(info)
        {
            return text + info
        }
    }


}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QMetaObject>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    engine.load(url);

    //C++调用qml
    auto root = engine.rootObjects();//拿到所有对象的列表
    //找出列表中的第一个
    auto labelqml = root.first()->findChild<QObject*>("labelcpp");//名字要与main.qml中的 objectName: 'labelcpp' 相同
    QVariant ret;
    //调用上述实例化的名字,main.qml中对应函数名,将返回到上述定义的ret中
    QMetaObject::invokeMethod(labelqml, "getText",Q_RETURN_ARG(QVariant, ret));
    //如果有参数要传入调用宏Q_ARG(QVariant,"参数")
    QMetaObject::invokeMethod(labelqml, "getText",Q_RETURN_ARG(QVariant, ret), Q_ARG(QVariant, " jie"));
    qDebug() << ret.toString();

    return app.exec();
}

值得注意的是,一般不会使用C++的方法去调用qml中的方法。

下面给这两种方法价绍了如何使用qml创建的按钮调用cpp的槽函数,一种方式是直接在qml调用函数,另一种方式是通过注册信号槽调用

如何在qml中调用C++的方法函数

main.cpp

#include "./person.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QMetaObject>
#include <QQmlContext>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    Person p1("smore", 32);
    //方法1:注册一个单例。命名,版本号1.0 对象名,实例对象名
//  qmlRegisterSingletonInstance("pModule", 1, 0, "Person", &p1);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    engine.load(url);
	//方法2:这种方法在qml文件中会有提示自动补全的功能,直接注册到其中
    auto context = engine.rootContext();
    context->setContextProperty("Person", &p1);

    return app.exec();
}

第一步就完成了,那如何通过注册好以后在qml中如何调用C++的函数?
第二步:就是将调用函数前要加入Q_INVOKABLE 宏,这样这个函数才能够在qml中调用
最后一步,通过在main.cpp中注册某个类,通过这个注册好的版本号引入对应要调用的qml文件中,然后直接通过 类.函数 调用对应的函数

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5 as Controls

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Controls.Button
    {
        text: 'Button1'
        onClicked: Person.printInfo()
    }

}

#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QString>

class Person : public QObject
{
    Q_OBJECT

public:
    using QObject::QObject;

    Person(QString name, quint8 age);
    Q_INVOKABLE void printInfo()const noexcept;
private:
    QString m_name;
    quint8 m_age;
};

#endif // PERSON_H




=============
#include "person.h"
#include <QDebug>

Person::Person(QString name, quint8 age) : m_name(name), m_age(age)
{

}

void Person::printInfo()const noexcept
{
    qDebug() << "name: " << m_name <<" age: " << m_age;
}

如何使用qml调用按钮的信号槽

(1)使用默认的clicked()信号

在person头文件中注册槽函数

public slots:
    void slotInfo()const noexcept;

实现方法

void Person::slotInfo()const noexcept
{
    qDebug() << __FUNCTION__ << "this is slot function";
}

主函数中调用
其中,要通过调用引擎获取到对应的按钮,然后通过这个按钮写信号槽的连接connect函数

    //C++调用qml
    Person p1("smore", 32);
    auto root = engine.rootObjects();
    auto pushButton = root.first()->findChild<QObject*>("smoreButton");
//比较好用的一种
    QObject::connect(pushButton,SIGNAL(clicked()), &p1, SLOT(slotInfo()));

QML源文件实现方法

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5 as Controls


Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Controls.Button
    {
        objectName: "smoreButton"
        text: 'Button1'
        onClicked: Person.printInfo()
    }

}

总结:就是在qml中注册按钮后在cpp中使用信号槽的方式,前提是先获取到按钮和对象。

(2)qml的按钮中直接注册信号发送到槽函数(QML中设置信号)

还有一种方式:直接在qml中写入信号,通过这个信号调用cpp中的函数槽方法:
main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5 as Controls


Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Controls.Button
    {
        objectName: "smoreButton"
        property int count: 0
        signal signalInfo(int count)
        text: 'Button1'
        onClicked:
        {
            Person.printInfo();
            ++count;
            if(count % 2 === 0)
                signalInfo(count);
        }
    }

}

person类

#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QString>

class Person : public QObject
{
    Q_OBJECT

public:
    using QObject::QObject;

    Person(QString name, quint8 age);
    Q_INVOKABLE void printInfo()const noexcept;

public slots:
    void slotInfo(int count)const noexcept;
private:
    QString m_name;
    quint8 m_age;
};

#endif // PERSON_H

#include "person.h"
#include <QDebug>

Person::Person(QString name, quint8 age) : m_name(name), m_age(age)
{

}

void Person::printInfo()const noexcept
{
    qDebug() << "name: " << m_name <<" age: " << m_age;
}

void Person::slotInfo(int count)const noexcept
{
    qDebug() << __FUNCTION__ << "this is slot function" << count;
}

main.cpp

#include "./person.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QMetaObject>
#include <QQmlContext>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    Person p1("smore", 32);
//    qmlRegisterSingletonInstance("pModule", 1, 0, "Person", &p1);


    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    engine.load(url);

    auto context = engine.rootContext();
    context->setContextProperty("Person", &p1);

    //C++调用qml
    auto root = engine.rootObjects();
    auto pushButton = root.first()->findChild<QObject*>("smoreButton");

    QObject::connect(pushButton,SIGNAL(signalInfo(int)), &p1, SLOT(slotInfo(int)));

    return app.exec();
}

上面这两种,一种是

(3)在qml中设置cpp中的信号槽函数


signals:
    void signalQmlCall() const;
 	//void signalQmlCall(QString) const;
void Person::printInfo()const noexcept
{
    qDebug() << "name: " << m_name <<" age: " << m_age;
    emit signalQmlCall();
    //emit signalQmlCall(m_name);
}

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5 as Controls


Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Controls.Button
    {
        objectName: "smoreButton"
        property int count: 0
        signal signalInfo(int count)
        text: 'Button1'
        onClicked:
        {
            Person.printInfo();
        }
    }

    Connections
    {
        target: Person
        function onSignalQmlCall()
        //function onSignalQmlCall(value)
        {
            console.log('cpp signal')
            console.log('cpp signal',value)
        }
    }

}

输出
name: “smore” age: 32
qml: cpp signal

其余方式与上述(2)中的代码一样

(4)从录入到qml的方法

这种就是调用对应类中的函数方法在qml
第一种方法:
前言 : 这个过程通过在qml中设置对应的属性值再从cpp中的方法函数中调用对应的函数

遇到的错误:
qml调用function方法函数的时候开头字母不能大写;
quint32 设置年龄的时候如果设置成quint8 或者quint64 都会报错,应该是quint8 代表的不是int类型,代表的是unchar类型,quint64不知道是为什么

main.cpp

#include "./person.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QMetaObject>
#include <QQmlContext>
#include <QDebug>

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    Person person("smore", 32);
    qmlRegisterType<Info>("smoreModule", 1, 0, "Info");//注入一个类型到qml文档中,这样qml中才能调用Info这个类qml文档中

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);

    auto context = engine.rootContext();
    context->setContextProperty("Person", &person);

    engine.load(url);

    return app.exec();
}

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import smoreModule 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Button
    {
        objectName: "jieButton"
        text: 'click' + info.name + ' ' + info.age + ' ' + Qt.formatDateTime(info.date,'yyyy-MM-dd hh:mm:ss')
        onClicked:
        {
            Person.printInfo();
        }


    }

    Connections
    {
        target: Person
        function onqmlCall(value)
        {
            console.log('cpp signal',value)
        }
    }

    Info{
        id: info
        name: 'smart'
        age: 1
        date: new Date()
    }

}

person类

#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QString>
#include <QDate>


class Info : public QObject
{
    Q_OBJECT
    //注册一个属性,才能在qml中调用出来
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY signalname)
    Q_PROPERTY(quint64 age READ getAge WRITE setAge NOTIFY signalage)
    Q_PROPERTY(QDate date READ getDate WRITE setDate NOTIFY signaldate)
public:
    using QObject::QObject;
    void setName(QString name)noexcept;
    QString getName() const noexcept;
    void setAge(quint32 age) noexcept;
    quint32 getAge() const noexcept;
    void setDate(QDate date)noexcept;
    QDate getDate() const noexcept;

signals:
    void signalname();
    void signalage();
    void signaldate();
private:
    QString m_name;
    quint32 m_age;
    QDate m_date;
};


class Person : public QObject
{
    Q_OBJECT

public:
    using QObject::QObject;
    Person(QString name, quint8 age);
    Q_INVOKABLE void printInfo()const noexcept;// qml call


signals:
    void qmlCall(QString) const;
private:
    QString m_name;
    quint8 m_age;
};

#endif // PERSON_H


#include "person.h"
#include <QDebug>

Person::Person(QString name, quint8 age) : m_name(name), m_age(age)
{

}

void Person::printInfo()const noexcept
{
    qDebug() << "name: " << m_name <<" age: " << m_age;
    emit qmlCall(m_name);
}


void Info::setName(QString name) noexcept
{
    m_name= qMove(name);
    emit signalname();
}
QString Info::getName() const noexcept
{
    return m_name;
}
void Info::setAge(quint32 age) noexcept
{
    m_age = age;
    emit signalage();
}
quint32 Info::getAge() const noexcept
{
    return m_age;
}
void Info::setDate(QDate date) noexcept
{
    m_date = date;
    emit signaldate();
}
QDate Info::getDate() const noexcept
{
    return m_date;
}

第二中方法:
Q_ELEMENT的这种方法QT自己找不到对应文件,先搁置起来

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: QWidget是Qt框架中的一个基类,用于构建传统的基于C++的GUI界面,而QML是一种用于构建现代、动态用户界面的声明性语言。在QWidget与QML结合使用时,可以借助QQuickWidget类将QML界面嵌入到QWidget中,实现二者的交互。 首先,我们需要在Qt项目中添加一个QQuickWidget部件。在QWidget的构造函数中,可以创建一个QQuickWidget对象,并将其设置为QWidget的子部件,通过设置QQuickWidget的源QML文件,可以指定要加载的QML界面。 接下来,可以在QML界面中定义一些交互的信号与槽。例如,在QML中定义一个点击按钮的信号与槽,以实现按钮点击时的反馈效果。在QML中,可以使用Signal类型定义一个信号,然后在按钮的点击事件中触发信号。在QWidget中,可以通过connect函数连接QML中定义的信号与槽,实现二者的交互。 具体实现代码如下: ```cpp // QWidget类的构造函数 MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { QQuickWidget *qmlWidget = new QQuickWidget(this); qmlWidget->setSource(QUrl("qrc:/main.qml")); // 设置QML文件路径 // 定义一个槽函数,用于接收来自QML界面的信号 connect(qmlWidget->rootObject(), SIGNAL(buttonClicked()), this, SLOT(onButtonClicked())); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(qmlWidget); setLayout(layout); } // QWidget类的槽函数,用于处理来自QML界面的信号 void MyWidget::onButtonClicked() { qDebug() << "Button clicked!"; } ``` 在上述代码中,我们通过QQuickWidget加载了一个名为main.qmlQML文件,并连接了其定义的buttonClicked信号和MyWidget类的onButtonClicked槽函数。 这样,在QML中按钮的点击事件中触发buttonClicked信号时,MyWidget的onButtonClicked槽函数将被调用,并打印出"Button clicked!"的相关信息。 通过以上方法,我们可以在QWidget和QML之间实现信号槽的交互,实现更加复杂和灵活的用户界面交互效果。 ### 回答2: QWidget是Qt的一个基础类,用于创建可视化的窗口应用程序。而QML是一种声明性语言,用于创建用户界面。在学习QML时,我们可以将QWidget与QML结合使用,并通过信号槽机制实现二者的交互。 要在QWidget中使用QML,我们首先需要创建一个QQuickWidget对象。QQuickWidget是一个可嵌入QML内容的QWidget子类。可以通过调用setSource函数指定QML文件的路径,然后将QQuickWidget对象添加到QWidget的布局中。 在QML中,我们可以定义信号和槽函数。信号是在某些事件发生时发出的通知,而槽函数则是接收信号并执行特定操作的函数。在QML中,我们可以使用signal关键字定义信号,使用on关键字将信号连接到相应的槽函数。 在QWidget中,我们可以使用QMetaObject::connectSlotsByName函数将QML中的信号和QWidget中的槽函数进行连接。这样,当QML中的信号触发时,对应的槽函数就会被调用。 例如,假设我们在QML中定义了一个按钮,当按钮被点击时,会触发一个名为buttonClicked的信号。我们可以在QWidget中定义一个名为onButtonClicked的槽函数,并将其与QML中的buttonClicked信号进行连接。当按钮被点击时,QWidget中的onButtonClicked槽函数就会被调用。 通过QWidget与QML的结合使用,我们可以充分发挥两者的优势,实现更加灵活和交互性强的用户界面。同时,通过信号槽机制,我们可以方便地在QWidget与QML之间进行数据传递和状态更新,提高数据的实时性和可靠性。 ### 回答3: 在学习QML的过程中,我们可能需要将Qt Widgets和QML结合使用,并实现信号槽的交互QML是一种用于创建用户界面的声明性语言,而Qt Widgets是Qt框架中用于创建传统桌面应用程序的类库。 要将QWidget与QML结合使用,我们可以使用Qt Quick Controls 2模块中的QQuickWidget类。该类允许我们将QML视图嵌入到QWidget应用程序中,以便在QMLQt Widgets之间进行交互。 首先,我们需要在Qt Widgets应用程序中创建一个QQuickWidget,并设置它要显示的QML文件路径: QQuickWidget *qmlWidget = new QQuickWidget; qmlWidget->setSource(QUrl("qrc:/qml/main.qml")); qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); 然后,我们可以通过将QWidget的指针传递给QML文件,来在QML中访问Qt Widgets对象。例如,在QML文件中可以这样定义一个按钮: import QtQuick.Controls 2.15 Button { id: myButton text: "Click me" onClicked: { // 调用Qt Widgets中的槽函数 myWidget.mySlot() } } 这里,我们假设QWidget类的对象被指定为myWidget。在按钮的onClicked信号中,我们可以调用myWidget对象的名为mySlot的槽函数。 要实现从QMLQt Widgets的信号传递,我们需要在QWidget的代码中定义一个槽函数,并在QML中使用Qt信号。例如,在QWidget的头文件中定义一个槽函数: public slots: void mySlot(); 然后,在QML文件中,可以这样发出信号: import QtQuick.Controls 2.15 Button { id: myButton text: "Click me" onClicked: { // 发出信号 mySignal() } } 这里,我们定义了一个名为mySignal的信号。在QML中的点击事件中,我们发出了该信号。 在QWidget类的代码中,我们可以连接这个信号到一个槽函数,以便执行相应的操作。例如: connect(myQmlWidget->rootObject(), SIGNAL(mySignal()), this, SLOT(mySlot())); 通过这种方式,我们可以在QWidget和QML之间建立信号槽的交互,实现二者之间的通信。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值