QT QML嵌入Widget窗体并通信

目的

qml怎么嵌入widget的窗体内,并进行通信,这里用示例进行说明

1.创建工程

创建工程后,在pro中加入 QT += quickwidgets

2.创建资源文件

创建资源文件src.qrc,创建main.qml并加入资源文件中

3.创建窗体并关联

创建一个widget,并在里面加入一个layout用来放qml窗体。编辑widget.h文件,引入头文件#include <QQuickWidget>。创建qml窗体指针QQuickWidget *qmlWidget;, 增加两个被调用的函数

Q_INVOKABLE void doSomething();

public slots:

void printWidgetData();

完整代码

复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QQuickWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //Q_INVOKABLE表示加入元对象系统,可以通过qml调用
    Q_INVOKABLE void doSomething();

public slots:
    void printWidgetData();

private:
    Ui::Widget *ui;
    QQuickWidget *qmlWidget;
};
#endif // WIDGET_H

在widget.cpp文件中,创建qml窗体qmlWidget = new QQuickWidget(this);,设置窗体的源qmlWidget->setSource(QUrl("qrc:/main.qml"));,然后设置一些qml属性,再把widget设置成qml的属性,并把qml放入widget的布局中,这样就关联起来了。代码是:

复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QQmlContext>
#include <QUrl>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    qmlWidget = new QQuickWidget(this);
    qmlWidget->setSource(QUrl("qrc:/main.qml"));

    //使root item适应窗口
    qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

    qmlWidget->setClearColor(Qt::transparent);

    qmlWidget->setAttribute(Qt::WA_AlwaysStackOnTop);

    //将qml窗体放入layout中
    ui->gridLayout_all->addWidget(qmlWidget);

    //将widget对象设置成qml的属性
    qmlWidget->rootContext()->setContextProperty("cppController", this);
}

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

void Widget::doSomething()
{
    qDebug()<<"widget method "<<__FUNCTION__<<" is called";
}

void Widget::printWidgetData()
{
    qDebug() << "widget method " << __FUNCTION__ << " is called";
}

上面的步骤完成后,就已经可以运行了,完成了qml嵌入widget窗体的目标。

4.在qml中调用

为了使qml内容更直观,在里面增加了一个按钮。同时为了关连数据,按钮中调用了widget的函数。main.qml代码为

复制代码
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
    anchors.fill: parent
    color: "black"
    visible: true
    Button {
        id: btn
        width: 100
        height: 100
        x:400
        y:1
        text: "button"
        onClicked: {
            console.log("button pressed")
            cppController.doSomething()
            cppController.printWidgetData()
        }

    }
}

现在运行程序,界面是

点击按钮,终端会打印:

qml: button pressed

widget method doSomething is called

widget method printWidgetData is called

5. qml增加函数,widge访问qml中的函数

function printData() {

console.log("qml function is called")

}

在widget.cpp文件中获得qml的root item对象,然后访问printData()函数,还可以设置属性,具体代码为

main.qml

复制代码
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
    anchors.fill: parent
    color: "black"
    visible: true
    Button {
        id: btn
        width: 100
        height: 100
        x:400
        y:1
        text: "button"
        onClicked: {
            console.log("button pressed")
            cppController.doSomething()
            cppController.printWidgetData()
        }

    }

    function printData() {
        console.log("qml function is called")
    }
}

widget.cpp

复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QQmlContext>
#include <QUrl>
#include <QQuickItem>
#include <QMetaObject>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    qmlWidget = new QQuickWidget(this);
    qmlWidget->setSource(QUrl("qrc:/main.qml"));

    //使root item适应窗口
    qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

    qmlWidget->setClearColor(Qt::transparent);

    qmlWidget->setAttribute(Qt::WA_AlwaysStackOnTop);

    //将qml窗体放入layout中
    ui->gridLayout_all->addWidget(qmlWidget);

    //将widget对象设置成qml的属性
    qmlWidget->rootContext()->setContextProperty("cppController", this);
}

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

void Widget::doSomething()
{
    qDebug()<<"widget method "<<__FUNCTION__<<" is called";
}

void Widget::printWidgetData()
{
    qDebug() << "widget method " << __FUNCTION__
             << " is called, call qml function next";

    QQuickItem *rootItem = qmlWidget->rootObject();     //获取qml的对象
    QMetaObject::invokeMethod(rootItem, "printData");   //调用qml函数
    rootItem->setProperty("color", QColor("green"));    //还可以设置属性
}

运行程序,点击按钮,得到界面和输出是

这里我把窗体改成了绿色属性,然后通过qml的点击事件处理访问widget函数,用widget函数再访问qml函数:onClicked -> printWidgetData()->printData()。

结语

qml可以嵌入widget窗体,也可以互相调用函数。基本的数据通了以后,详细的可以根据实际情况修改,灵活多变,比如widget改成mainwindow也是可以的,由widget触发调用qml中的函数等。

相关推荐
sycmancia35 分钟前
Qt——Qt中的事件处理(一)
开发语言·qt
代钦塔拉2 小时前
第二篇:VS2019 + Qt5.9.9 中文乱码实战:源码GB2312不乱码、文件写入与跨平台方案
开发语言·qt
sycmancia4 小时前
Qt中的事件处理(二)
开发语言·qt
hanbr4 小时前
Qt 进阶开发:主窗口、对话框、布局与常用控件全解析
qt
小短腿的代码世界5 小时前
Qt时间日期处理与QTimer高级应用:从毫秒级精度到跨平台定时器的完整架构解析
开发语言·qt·架构
小短腿的代码世界6 小时前
QGC飞控参数系统架构深度解析:从XML到飞控寄存器的参数同步引擎
qt·microsoft·ui
小短腿的代码世界6 小时前
QGC固件升级与引导加载架构深度解析:从Bootloader握手到固件校验的完整流程
qt·性能优化·架构
buhuizhiyuci7 小时前
【QT-百日筑基篇】打完完怪,开始学炼丹, 前往藏书阁寻找对应材料的信息,并前往去寻找对应材料-QT信号和槽
开发语言·qt
Ulyanov7 小时前
PySide6 + QML 混合编程全景解析:从底层原理到企业级实战
python·pyside6·qml·雷达电子对抗
小短腿的代码世界7 小时前
QtitanRibbon深度解析:从微软Office UI到Qt跨平台Ribbon框架的完整架构实现
qt·microsoft·ui