文章目录
一、demo效果图
该实例,主要是在已有的QWidget工程中,加入qml工程,方便qml项目的开发与维护,让qml开发者更好的上手qml。
(1)展示了c++和qml常见的交互方式。
(2)qwidget工程如何加载qml工程,如何加载自己实现的qml tool库。
(3)创建无边框qml界面,支持拖拽,窗口的缩小与展开,界面的分段实现。
(4)展示一个简单的堆栈窗口(SwipeView),相当于QStackedWidget,管理多个子窗口页面。
(5)实现一个简单的列表框(ListView),相当于QListWidget,定时请求网络数据,展示学生信息,将view和model进行分离,降低界面与数据的耦合。
(6)点击学号、年龄,实现了列表数据的排序。
二、c++和qml交互的基本方式
两者的交互是核心,简单学习后,可以快速上手。方式有很多种,有的比较繁杂,不易理解,此处只使用了最方便使用的方法,满足基本的交互。基本的方式不外乎有四种。
- qml 调用 C++ 类对象
- C++ 类对象调用 qml
- qml 给 C++ 发送信号
- C++ 给 qml 发送信号
1、qml 调用 C++ 类对象
需要先将C++类(MainQuickView、MyWindow)注册。和qml相关的C++类,最好都进行注册。
// cpp
class MainQuickView : public QQuickView
{
Q_OBJECT
public:
MainQuickView(QQuickView *parent = nullptr);
~MainQuickView() override;
void initialzeUI();
protected:
};
void MainQuickView ::initialzeUI()
{
// 注册,为了qml中可以直接访问C++对象
this->rootContext()->setContextProperty("myQuickView", this);
MyWindow *w = new MyWindow();
this->rootContext()->setContextProperty("myWindow", w);
...
}
这样C++的信号
,public槽函数
,Q_INVOKABLE 修饰的类成员函数
// cpp
class MyWindow : public QWidget
{
Q_OBJECT
public:
MyWindow();
// Q_INVOKABLE可以将C++函数暴漏给qml引擎,注册到元对象系统
Q_INVOKABLE void invokableMethod();
signals:
void dataChanged();
public slots:
void refresh();
};
就可以在qml中调用
// main.qml
Rectangle {
id: root
width: 1200
height: 800
onClicked: {
myWindow.showNormal(); // showNormal是QWidget父类的槽函数
}
}
2、C++ 类对象调用 qml
需要先找到你想访问的qml中,名为"topRect"的QQuickItem对象
// cpp
QQuickItem* topRect = this->rootObject()->findChild<QQuickItem*>("topRect");
然后再访问qml实现的函数,“setTitleText”,该函数标题3展示(qml 给 C++ 发送信号)
// cpp
QMetaObject::invokeMethod(topRect, "setTitleText", Q_ARG(QVariant, QString::fromLocal8Bit("Qml窗口标题")));
3、qml 给 C++ 发送信号
qml发送信号
// qml
Rectangle {
id: root
signal sendTopRectPos(var x, var y) // 定义信号
function setTitleText(text) {
titleText.text = text
}
MouseArea {
// ...
property point clickPos: "0, 0"
onPressed: {
clickPos = Qt.point(mouse.x, mouse.y)
}
onPositionChanged: {
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
sendTopRectPos(delta.x, delta.y) // 发送信号
}
}
}
C++绑定槽函数,该操作可以实现无边框窗口的拖拽
// cpp
QQuickItem* topRect = this->rootObject()->findChild<QQuickItem*>("topRect");
if (topRect) {
connect(topRect, SIGNAL(sendTopRectPos(QVariant, QVariant)),
this, SLOT(onSendTopRectPos(QVariant, QVariant)));
4、C++ 给 qml 发送信号
C++发送信号
// cpp
void MainQuickView::minMaxQmlWindow()
{
int nStudent = 10;
emit refreshStuCount(nStudent); // 发送信号
}
qml绑定槽函数
// qml
Rectangle {
id: root
function onRefreshStuCount(nStudent){
// ...
}
Component.onCompleted: {
mainQuickView.refreshStuCount.connect(onRefreshStuCount) // 绑定qml函数
}
三、关键代码
1、工程结构图
2、c++代码
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWindow)
, m_pQuickVew(nullptr)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if (!m_pQuickVew)
{
// 加载qml包含两种方式,一种是QQuickView,一种是QQmlApplicationEngine
// 当前使用第一种方式,MainQuickView继承自QQuickView
m_pQuickVew = new MainQuickView();
m_pQuickVew->setObjectName("quickView");
}
m_pQuickVew->show();
}
MainQuickView.cpp
static const char* s_mainPath = "qrc:/qml/main.qml";
MainQuickView::MainQuickView(QQuickView *parent)
: QQuickView(parent)
, m_bMin(false)
{
this->setFlags(Qt::Window | Qt::FramelessWindowHint);
this->setTitle(QString::fromLocal8Bit("图书馆"));
initialize();
setMoveable();
setTitleData();
}
MainQuickView::~MainQuickView()
{
}
void MainQuickView::initialize()
{
// 初始化view 和 model,降低耦合,提高可维护性
if (!m_pStudentInfoView)
m_pStudentInfoView = new StudentInfoView();
if (!m_pStudentInfoModel)
m_pStudentInfoModel = m_pStudentInfoView->getStudentInfoMode();
// ...其他功能
initialzeUI();
}
void MainQuickView::initialzeUI