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中的函数等。

相关推荐
小小码农Come on15 小时前
QT实现线程4种方法
qt
jf加菲猫19 小时前
第15章 文件和目录
开发语言·c++·qt·ui
清风玉骨1 天前
C++/Qt从零开始编译使用libxlsxwriter库
开发语言·qt
jingshaoqi_ccc1 天前
使用QT6创建一个可编辑的表格并导出和载入
c++·qt·表格
机器视觉知识推荐、就业指导2 天前
Qt:真正的门槛不是入门,而是维护
开发语言·qt
米优2 天前
qgis电子地图二次开发---比例尺
qt·qgis
谁刺我心2 天前
[QML]Functional功能型控件-虚拟键盘
开发语言·qml·虚拟键盘
雾岛听蓝2 天前
Qt操作指南:状态栏、浮动窗口与对话框使用
开发语言·经验分享·笔记·qt
楚Y6同学2 天前
QT C++之保存界面设置为配置文件
c++·qt·保存配置