这里写自定义目录标题
QML与C++ 交互详解
这里我们分别介绍下QML 如何访问C++ 类,以及C++ 如何与QML 交互。
(一) QML如何访问C++ 类:
- 话不多说我们先看代码:
#include "fpsitem.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
qmlRegisterType<FpsItem>("an.item", 1, 0, "FpsItem");
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);
return app.exec();
}
#ifndef FPSITEM_H
#define FPSITEM_H
#include <QQuickItem>
class FpsItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(int fps READ fps NOTIFY fpsChanged)
public:
FpsItem(QQuickItem *parent = nullptr);
int fps() const;
signals:
void fpsChanged();
private:
int m_fps = 0;
int m_frameCount = 0;
};
#endif // FPSITEM_H
#include "fpsitem.h"
#include <QQuickWindow>
#include <QTimer>
FpsItem::FpsItem(QQuickItem *parent)
: QQuickItem(parent)
{
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [this]{ m_fps = m_frameCount; m_frameCount = 0; emit fpsChanged(); });
connect(this, &QQuickItem::windowChanged, this, [this]{
if (window())
connect(window(), &QQuickWindow::afterRendering, this
, [this]{ m_frameCount++; }, Qt::DirectConnection);
});
timer->start(1000);
}
int FpsItem::fps() const
{
return m_fps;
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Shapes 1.15
import an.item 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("FpsItem Test")
FpsItem {
id: fpsItem
}
Item {
id: back
anchors.fill: parent
layer.enabled: true
layer.smooth: true
layer.samples: 8
property bool running: false
MouseArea {
anchors.fill: parent
onClicked: parent.running = !parent.running;
}
PathAnimation {
target: ball
running: back.running
duration: 4000
loops: -1
path: Path {
startX: -ball.width * 0.5
startY: back.height - ball.height * 0.5
PathCurve { x: back.width * 0.8 - ball.width * 0.5; y: back.height * 0.8 - ball.height * 0.5 }
PathCurve { x: back.width * 0.2 - ball.width * 0.5; y: back.height * 0.2 - ball.height * 0.5 }
PathCurve { x: back.width - ball.width * 0.5; y: - ball.height * 0.5 }
}
}
Shape {
ShapePath {
strokeColor: "#ff1493"
fillColor: "transparent"
startX: 0
startY: back.height
PathCurve { x: back.width * 0.8; y: back.height * 0.8 }
PathCurve { x: back.width * 0.2; y: back.height * 0.2 }
PathCurve { x: back.width; y: 0 }
}
}
Rectangle {
id: ball
x: -width * 0.5
y: back.height - height * 0.5
width: 50
height: width
radius: width * 0.5
gradient: Gradient {
GradientStop { position: 0.20; color: "#af2020" }
GradientStop { position: 1.00; color: "#c27131" }
}
transformOrigin: Item.Center
transform: Rotation {
axis { x: 1; y: 1; z: 0 }
NumberAnimation on angle {
running: back.running
duration: 1000
loops: -1
from: 0
to: 360
}
}
}
Text {
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: 10
font.pointSize: 12
text: "FPS: " + fpsItem.fps
color: "red"
}
}
}
首先我们来看下main.cpp:
- qmlRegisterType方法: ,将会注册一个模块 an.item;组件的名字为:FpsItem
- QQmlApplicationEngine: 定义一个qml引擎;加载qml 文件
再来看看qml文件: - import an.item 1.0导入模块an.item
-
FpsItem { id: fpsItem } 使用组件,其中fpsItem中定义了一个属性fps可在qml中直接访问。
- 当然我们定义的FpsItem 是继承自QQuickItem的,无界面显示。如果想含有界面显示的可以继承QQuickWidget 或者是QQuickWindow 等。
- 这里对于Q_PROPERTY 这些QT 封装类的技巧就不在一一介绍,
- 感兴趣的同学可以去查阅下 Q_INVOKABLE 作为导出方法体供qml 直接使用。
- 关于C++ 如何与C++ 通信,下次再讲解。