24. 在QML界面中嵌入QWidget窗口
创始人
2025-05-29 14:00:17
0

1. 说明:

目前QT官方主推的界面开发方式是采用QML进行界面设计,但在QML未流行之前,很多的项目都是采用QWidget开发的,把之前的代码全部转换为QML代码显然工作量非常大,如果能将QWidget窗口嵌入到QML界面中,那么开发效率将提高很多,且QML无法实现的功能也能借助于QWidget框架进行实现。
本篇文章将介绍一种方式来实现QML和QWidget的混合开发
其中,参考了两篇文章:
第一篇:震惊!QWidget竟然可以嵌入到QML中,QMl窗口句柄竟然是这样获取,这篇文章能够成功将QWidget窗口嵌入到QML界面中,但无法实现QWidget窗口的的任意布局。
第二篇:在QML 中,嵌入QWidget 对象,这篇文章介绍了另一种思路,按照其说法是可以实现QWidget窗口在QML界面中任意布局的,但其博客里提供的代码有残缺,真正移植到自己的项目中还是无法实现功能。
所以,本文章结合上述两位大佬的思路,融合者两种方法,实现了预期效果。
效果展示:

QML_QWidget

2. 实现步骤:

整体的项目框架如图所示:因为要使用到QWidget,所以要在项目的.pro文件中加入quickwidgets库:QT += quick quickwidgets
在这里插入图片描述

2.1 第一步:

既然是要将QWidget窗口嵌入到QML界面中,那么先创建一个QWidget窗口,使用自带的Qt Designer设计大师进行简单布局,在其中放置一个tabWidget控件,简单设置一下样式,如下图所示:
在这里插入图片描述
这里只是简单的设计了一下QWdiget的窗口,并没有实现什么功能,所以代码相对简单,如下所示:
unitywidget.h:

#ifndef UNITYWIDGET_H
#define UNITYWIDGET_H#include namespace Ui {
class unityWidget;
}class unityWidget : public QWidget
{Q_OBJECTpublic:explicit unityWidget(QWidget *parent = nullptr);~unityWidget();private:Ui::unityWidget *ui;
};#endif // UNITYWIDGET_H

unitywidget.cpp:

#include "unitywidget.h"
#include "ui_unitywidget.h"unityWidget::unityWidget(QWidget *parent) :QWidget(parent),ui(new Ui::unityWidget)
{ui->setupUi(this);
}unityWidget::~unityWidget()
{delete ui;
}

2.2 第二步:

因为想要在QML界面中像其他控件一样使用锚布局对QWdiget窗口进行布局,但是直接加进来的QWidget窗口是无法实现的,所以要自定义一个辅助类,这个辅助类就是专门对QWdiget窗口进行布局的,该类的构造函数需要两个参数,一个是要加载到QML界面中的QWdiget窗口,另一个是QML界面中的一个Item控件,这个Item控件将会成为QWdiget窗口的父对象,在QML界面中对这个Item布局,即可间接实现对QWdiget窗口布局。辅助类的代码如下:
WdigetAnchorHelper.h:

#ifndef WDIGETANCHORHELPER_H
#define WDIGETANCHORHELPER_H#include 
#include 
#include 
#include class WdigetAnchorHelper : public QObject
{Q_OBJECTpublic:explicit WdigetAnchorHelper(QWidget* mWidget, QQuickItem* mItem);~WdigetAnchorHelper();private://实时更新widge的位置void updateGeometry();private://QPointer用于创建一个指针 (效果等同于 QWidget* _mWidgetQPointer _mWidget;QPointer _mQuickItem;
};#endif // WDIGETANCHORHELPER_H

WdigetAnchorHelper.cpp:

#include "wdigetanchorhelper.h"WdigetAnchorHelper::WdigetAnchorHelper(QWidget* mWidget, QQuickItem* mItem):_mWidget(mWidget), _mQuickItem(mItem)
{//QML中的Item相关属性发生变化时,执行更新槽函数connect(_mQuickItem, &QQuickItem::xChanged, this, &WdigetAnchorHelper::updateGeometry);connect(_mQuickItem, &QQuickItem::yChanged, this, &WdigetAnchorHelper::updateGeometry);connect(_mQuickItem, &QQuickItem::widthChanged, this, &WdigetAnchorHelper::updateGeometry);connect(_mQuickItem, &QQuickItem::heightChanged, this, &WdigetAnchorHelper::updateGeometry);//初始化位置updateGeometry();
}WdigetAnchorHelper::~WdigetAnchorHelper()
{}void WdigetAnchorHelper::updateGeometry()
{if (_mQuickItem){_mWidget->setGeometry(_mQuickItem->x(),_mQuickItem->y(),_mQuickItem->width(),_mQuickItem->height());}
}

2.3 第三步:

main.qml文件中,在根节点Window内添加一个Item控件,这个控件是用来装载即将加载进来的QWidget窗口的,本代码中,左部分显示一张图片,右部分显示QWidget窗口,代码如下所示:

import QtQuick 2.15
import QtQuick.Window 2.15Window {width: 500height: 300visible: truetitle: qsTr("QML QWidget")Image{width: parent.width/2height: parent.heightanchors.left: parent.leftsource: "qrc:/images/katong.jfif"}Item{objectName: "widgetItem"width: parent.width/2height: parent.heightanchors.right: parent.right}
}

2.4 第四步:

在项目的main.cpp中,需要获取QML中的根元素以及相关控件对象,并设置自定义的窗口句柄和其父窗口,一些其他的注意事项和具体解释详看代码注释,整体代码如下:

#include 
#include 
#include 
#include 
#include 
#include #include "unitywidget.h"
#include "wdigetanchorhelper.h"int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif//创建项目时默认使用的是QGuiApplication,但因为要嵌入QWidget窗口//所以要使用QApplicationQApplication 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);QObject *QmlObj = engine.rootObjects().at(0);//获取QML当中的根对象QWindow *QmlWindow = qobject_cast(QmlObj);//将跟对象转换成QWindow类型WId parentHWND = QmlWindow->winId();//获取Qml窗口的句柄QQuickItem* unityItem = QmlObj->findChild("widgetItem");//获取QML中用于装载widget的ItemunityWidget* mUnityWidget = new unityWidget(); //自定义widget窗体mUnityWidget->setProperty("_q_embedded_native_parent_handle",QVariant(parentHWND));//给widget父对象句柄赋值mUnityWidget->winId();//必须调用,才能为widget创建句柄,否则将会失败mUnityWidget->windowHandle()->setParent(QmlWindow);//通过窗口句柄设置父窗口new WdigetAnchorHelper(mUnityWidget, unityItem);//将widget和Item加入自定义辅助类中,管理widget在QML中的布局mUnityWidget->show();//在QML界面中显示自定义widget窗口return app.exec();
}

3. 实际效果展示:

在这里插入图片描述

持续更新中,请大家多多关注…

相关内容

热门资讯

法律顾问能处理保险法律事务吗 在当今复杂的商业和法律环境中,保险法律事务对于企业和个人都至关重要。许多人会疑惑,法律顾问是否有能力...
海南国际清算所:依托海南自贸港... 编者按 随着我国多层次的商品市场体系持续完善,场外衍生品市场发展加速推进,其服务实体经济的核心价值正...
威少21+6+11约基奇空砍4... 【搜狐体育战报】北京时间11月23日NBA常规赛,客场作战的国王以128-123击败掘金。威斯布鲁克...
跨境电商高发!多部门共织“天罗... 东方网11月23日消息:11月21日,上海市人民检察院第三分院与上海海关缉私局、上海海警局、上海市第...
法律顾问能处理旅游法律事务吗 在旅游行业蓬勃发展的当下,各类旅游法律事务也日益增多,许多人会疑惑法律顾问是否能处理旅游法律事务。答...
法律顾问能处理哪些法律事务 在当今复杂多变的商业环境中,企业面临着各种各样的法律风险和挑战,法律顾问的重要性日益凸显。那么,法律...
原创 美... 美军的撤离速度印证了威慑效果。“尼米兹”号10月中旬进入南海后,10月26日接连发生两起舰载机坠机事...
王毅:中方绝不允许日本右翼势力... 当地时间2025年11月22日,中共中央政治局委员、外交部长王毅在杜尚别同塔吉克斯坦外长穆赫里丁举行...
上海特大案件曝光!涉案金额超亿... 今年以来,公安部会同金融监管总局开展打击金融领域黑灰产违法犯罪专项工作,对保险等领域违法犯罪进行重点...