QML与C++交互详解(二)
QML中连接C++ 的信号
- 话不多说:
/**
* @file BaseQmlWidget.h
* @author shijiaobing (503876187@qq.com)
* @brief QQuickWidget loaded Qml File to embed C++ QWidget
* @version 0.1
* @date 2022-09-21
*
* @copyright Copyright (c) 2022
*
*/
#ifndef _BASE_QML_WIDGET_H_
#define _BASE_QML_WIDGET_H_
#include <QQuickWidget>
#include "Ui_Export_Dll.h"
#include <QQuickItem>
class UIDLLEXPORT BaseQmlWidget : public QWidget
{
Q_OBJECT
public:
/**
* @brief Construct a new Base Qml Widget object
*
* @param url
* @param parent
*/
BaseQmlWidget(const QUrl &url, QWidget *parent = nullptr);
/**
* @brief Destroy the Base Qml Widget object
*
*/
virtual ~BaseQmlWidget();
/**
* @brief get QQuickWidget
*
* @return QQuickWidget*
*/
QQuickWidget *quickWidget();
protected:
/**
* @brief Create a Qml Widget object
*
*/
virtual void createQmlWidget();
/**
* @brief init layout
*
*/
virtual void initLayout();
/**
* @brief Set the Context Property object
*
*/
virtual void setContextProperty() = 0;
/**
* @brief init baseQmlWidget
*
*/
virtual void initBaseQmlWidget();
QQuickWidget *m_item = nullptr;
QUrl m_url;
};
#endif
#include "BaseQmlWidget.h"
#include <QUrl>
#include <QWidget>
#include <QHBoxLayout>
#include "FileHelper.h"
BaseQmlWidget::BaseQmlWidget(const QUrl &url, QWidget *parent)
:QWidget(parent),m_url(url)
{
}
BaseQmlWidget::~BaseQmlWidget() {
}
void BaseQmlWidget::initBaseQmlWidget()
{
createQmlWidget();
setContextProperty();
initLayout();
}
QQuickWidget* BaseQmlWidget::quickWidget() {
return m_item;
}
void BaseQmlWidget::createQmlWidget(){
m_item = new QQuickWidget();
m_item->quickWindow()->setPersistentOpenGLContext(true);
m_item->quickWindow()->setClearBeforeRendering(true);
m_item->setWindowFlag(Qt::FramelessWindowHint);
m_item->setClearColor(QColor(Qt::transparent));
m_item->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_item->setParent(parentWidget());
}
void BaseQmlWidget::initLayout() {
m_item->setSource(m_url);
QHBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setMargin(0);
layout->addWidget(reinterpret_cast<QWidget*>(m_item));
this->setLayout(layout);
}
/**
* @file TitleBar.h
* @author shijiaobing (503876187@qq.com)
* @brief 标题栏
* @version 0.1
* @date 2022-09-21
*
* @copyright Copyright (c) 2022
*
*/
#ifndef _TITLE_BAR_H_
#define _TITLE_BAR_H_
#include "BaseQmlWidget.h"
class TitleBarData;
class UIDLLEXPORT TitleBar : public BaseQmlWidget
{
Q_OBJECT
Q_PROPERTY(bool maxWindowFlag READ maxWindowFlag WRITE setMaxWindowFlag NOTIFY maxWindowFlagChanged)
public:
/**
* @brief Construct a new Title Bar object
*
* @param url
* @param parent
*/
explicit TitleBar(const QUrl &url, QWidget *parent = nullptr);
~TitleBar();
/**
* @brief 获取qml对象
*
* @return QList<QQuickItem *>
*/
QList<QQuickItem *> items();
/**
* @brief qml调用方法
*
* @return bool
*/
Q_INVOKABLE bool maxWindowFlag() const;
/**
* @brief Set the Max Window Flag object
*
* @param flag
*/
void setMaxWindowFlag(bool flag);
signals:
/**
* @brief 最大化通知界面
*
* @param flag
*/
void maxWindowFlagChanged(bool flag);
protected:
/**
* @brief Set the Context Property object
*
*/
virtual void setContextProperty() override;
private:
void initConnect();
bool m_maxWindowFlag = false;
QList<QQuickItem *> m_items;
};
#endif
#include "TitleBar.h"
#include <QQmlContext>
#include <QQmlEngine>
TitleBar::TitleBar(const QUrl &url, QWidget *parent)
: BaseQmlWidget(url, parent)
{
initBaseQmlWidget();
initConnect();
}
TitleBar::~TitleBar()
{
}
QList<QQuickItem*> TitleBar::items()
{
return m_items;
}
void TitleBar::setContextProperty() {
m_item->rootContext()->setContextProperty("titleBarData",this);
}
void TitleBar::initConnect()
{
auto items = m_item->rootObject()->childItems();
foreach(auto item, items) {
if (item->objectName() == "row") {
m_items.append(item);
}
}
}
void TitleBar::setMaxWindowFlag(bool flag) {
if (m_maxWindowFlag != flag) {
m_maxWindowFlag = flag;
emit maxWindowFlagChanged(m_maxWindowFlag);
}
}
bool TitleBar::maxWindowFlag()const {
return m_maxWindowFlag;
}
import QtQuick 2.14
import QtQml 2.14
import "./Controls"
Rectangle {
id: root
property bool isMaxWindow: false
objectName: "TitleBar"
signal closeBtnClick()
signal maxBtnClick()
signal minBtnClick()
signal restoreBtnClick()
signal menuBtnClick()
signal registerBtnClick()
signal buyBtnClick()
radius:root.isMaxWindow?0:10
color: "#2E2F30"
Text {
id: product_name_text
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 12
height:root.height
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
color: "#FFFFFF"
text: "123123213123"
}
Row {
spacing: 12
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
objectName: "row"
// verticalAlignment:Row.AlignVCenter
TitleButton {
id: registerBtn
objectName: "registerBtn"
imageUrlNomal: "qrc:/image/registerBtn_nomal.png"
imageUrlHover: "qrc:/image/registerBtn_hover.png"
imageUrlPressed: "qrc:/image/registerBtn_pressed.png"
onBtnClick: {
registerBtnClick()
}
}
TitleButton {
id: buyBtn
objectName: "buyBtn"
imageUrlNomal: "qrc:/image/buyBtn_nomal.png"
imageUrlHover: "qrc:/image/buyBtn_hover.png"
imageUrlPressed: "qrc:/image/buyBtn_pressed.png"
onBtnClick: {
buyBtnClick()
}
}
TitleButton {
id: menuBtn
objectName: "menuBtn"
imageUrlNomal: "qrc:/image/menuBtn_nomal.png"
imageUrlHover: "qrc:/image/menuBtn_hover.png"
imageUrlPressed: "qrc:/image/menuBtn_pressed.png"
onBtnClick: {
menuBtnClick()
}
}
TitleButton {
id: minBtn
objectName: "minBtn"
imageUrlNomal: "qrc:/image/minBtn_nomal.png"
imageUrlHover: "qrc:/image/minBtn_hover.png"
imageUrlPressed: "qrc:/image/minBtn_pressed.png"
onBtnClick: {
minBtnClick()
}
}
TitleButton {
id: maxBtn
objectName: "maxBtn"
imageUrlNomal: root.isMaxWindow ? "qrc:/image/restoreBtn_nomal.png" : "qrc:/image/maxBtn_nomal.png"
imageUrlHover: root.isMaxWindow ? "qrc:/image/restoreBtn_hover.png" : "qrc:/image/maxBtn_hover.png"
imageUrlPressed: root.isMaxWindow ? "qrc:/image/restoreBtn_pressed.png" : "qrc:/image/maxBtn_pressed.png"
onBtnClick: {
console.log("maxBtn"+titleBarData.maxWindowFlag)
if (root.isMaxWindow)
restoreBtnClick()
else
maxBtnClick()
}
}
TitleButton {
id: closeBtn
objectName: "closeBtn"
imageUrlNomal: "qrc:/image/closeBtn_nomal.png"
imageUrlHover: "qrc:/image/closeBtn_hover.png"
imageUrlPressed: "qrc:/image/closeBtn_pressed.png"
onBtnClick: {
closeBtnClick()
}
}
}
Rectangle {
id: background_left_bottom_rect
width: 10
height: 10
anchors.left: parent.left
anchors.bottom: parent.bottom
color: "#2E2F30"
}
Rectangle {
id: background_right_bottom_rect
width: 10
height: 10
anchors.right: parent.right
anchors.bottom: parent.bottom
color: "#2E2F30"
}
Connections{
target: titleBarData
function onMaxWindowFlagChanged(value){
console.log("onMaxWindowFlagChanged"+value)
root.isMaxWindow=value
}
}
}
void MainWindow::initConnect() {
connect(m_helper, &FramelessHelper::maximizedChanged, m_titileBar, &TitleBar::setMaxWindowFlag);
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(buyBtnClick()), this, SLOT(onBuyBtnClicked()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(menuBtnClick()), this, SLOT(onMenuBtnClicked()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(registerBtnClick()), this, SLOT(onRegisterBtnClicked()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(minBtnClick()), m_helper, SLOT(triggerMinimizeButtonAction()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(maxBtnClick()), m_helper, SLOT(triggerMaximizeButtonAction()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(closeBtnClick()), m_helper, SLOT(triggerCloseButtonAction()));
connect(m_titileBar->quickWidget()->rootObject(), SIGNAL(restoreBtnClick()), m_helper, SLOT(triggerMaximizeButtonAction()));
}
可以看出C++ 获取qml嵌入的quickwidget中的rootObject()方法获取到QQuickItem对象为qml 中的root,
此时由于qml 是支持qt 的原对象系统的,qml 文件在经过moc 编译后会含有信号函数,此时可以直接连接qml 中得信号。而C++ 中的对象也是同样的,这样我们就可以实现qml 与C++ 的通信啦。