参考文档:​​https://doc.qt.io/qt-6/qtqml-cppintegration-exposecppattributes.html​

注册可实例化的类型

先看一个例子,这个例子参考了这个文档:​​https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#registering-c-types-with-the-qml-type-system​

  1. 定义C++类型

#ifndef MESAGE_H
#define MESAGE_H

#include <QObject>

#include <QtQml/qqmlregistration.h>

class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
// 导出的类名
QML_NAMED_ELEMENT(MyMessage)
public:
explicit Message(QObject *parent = nullptr);
QString author(){
return m_author;
}
void setAuthor(QString author)
{
m_author = author;
emit authorChanged(m_author);
}
signals:
void authorChanged(QString author);
private:
QString m_author = "hello world";
};

#endif // MESAGE_H

  1. 配置.pro文件

CONFIG += qmltypes
QML_IMPORT_NAME = an.qt.messaging
QML_IMPORT_MAJOR_VERSION = 1
INCLUDEPATH += an/qt/messaging

Qt6中C++与QML混合编程--教程(1)_QT6

编译工程,编译时有一个警告,忽略它...

  1. 在QML文件中使用

import QtQuick
import QtQuick.Controls
import an.qt.messaging 1.0

Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle {
Text {
text: msg.author
}
}
property int count: 0
MyMessage {
id: msg
author: "author"
onAuthorChanged: console.log("changed")
}
Button {
x: 22
y: 100
text: "Button"
onClicked: {

msg.author = "clicked" + count;
count ++
}
}
}

运行结果

Qt6中C++与QML混合编程--教程(1)_QML与C++交互_02

小结

  • Message 继承自 QObject,并且在类中使用了Q_OBJECT宏
  • QML_NAMED_ELEMENT(MyMessage),MyMessage是在QML中可以直接使用的类名

MyMessage {
id: msg
author: "author"
onAuthorChanged: console.log("changed")
}

  • 在.pro工程文件中的配置

CONFIG += qmltypes
QML_IMPORT_NAME = an.qt.messaging
QML_IMPORT_MAJOR_VERSION = 1
INCLUDEPATH += an/qt/messaging

CONFIG += qmltypes就认为这是固定语法吧

QML_IMPORT_NAME = an.qt.messaging定义了包名

QML_IMPORT_MAJOR_VERSION = 1 定义的主版本号

  • QML文件中导入和使用

import an.qt.messaging 1.0
MyMessage {
id: msg
author: "author"
onAuthorChanged: console.log("changed")
}

教程

官方提供了一个教程示例:​​https://doc.qt.io/qt-6/qtqml-tutorials-extending-qml-example.html​

如运行示例?

Qt6中C++与QML混合编程--教程(1)_QT6_03

在输入框中输入“Writing QML Extensions with C++”

Qt6中C++与QML混合编程--教程(1)_QML与C++交互_04

在编辑模式下,展开extending-qml,右选择运行...

Chapter1: 创建新类型

目标:

  • 创建一个新类型PieChart,它有一个name和color属性
  • 在QML文件中可以这样使用PieChart
import Charts 1.0

PieChart {
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}
  • 最终在程序运行之后显示一个饼图

实现

定义类型

QML拓展要用到Qt的元对象系统,所以新类(PieChart)必须满足以下条件:

  • 继承自 QObject, 并且使用Q_OBJECT宏
  • 使用Q_PROPERTY宏声明属性
#include <QtQuick/QQuickPaintedItem>
#include <QColor>

class PieChart : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QColor color READ color WRITE setColor)
QML_ELEMENT

public:
PieChart(QQuickItem *parent = nullptr);

QString name() const;
void setName(const QString &name);

QColor color() const;
void setColor(const QColor &color);

void paint(QPainter *painter) override;

private:
QString m_name;
QColor m_color;
};

PieChart继承自​​QQuickPaintedItem​​​,继承这个类的目的是重载paint()函数,在这个函数中使用QPainter api执行绘图操作,或者你有别的目的:

  • 如果只是简单的数据类型,不需要显示,只需继承自QObject就可以了
  • 如果要拓展基于QObject(QObject或它的了类)类型的某个功能,直接用这个类替换即可(这好像是一句废话)
  • 如果要创建一个不需执行绘图操作的可见类型,需要继承自QQuickItem

PieChart做了什么事情:

qmake的设置

为了使用注册生效,还需要在项目文件(chapter1-basics.pro)中添加如下配置:

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

类的实现

  • 设置和获取m_name和m_color的简单实现
  • 在paint函数中绘制饼图
#include "piechart.h"
#include <QPainter>

//![0]
PieChart::PieChart(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
}
//![0]

QString PieChart::name() const
{
return m_name;
}

void PieChart::setName(const QString &name)
{
m_name = name;
}

QColor PieChart::color() const
{
return m_color;
}

void PieChart::setColor(const QColor &color)
{
m_color = color;
}

//![1]
void PieChart::paint(QPainter *painter)
{
QPen pen(m_color, 2);
painter->setPen(pen);
painter->setRenderHints(QPainter::Antialiasing, true);
painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
}
//![1]

在paint函数中用到了​​QPainter​​绘制饼形。

第37行中,boundingRect.adjusted(1, 1, -1, -1),四边都向内缩减了1个单位,所在QML中指定width/height时,饼形大小也会跟关改变。

在QML中使用PieChart

import Charts 1.0
import QtQuick 2.0

Item {
width: 300; height: 200

PieChart {
id: aPieChart
anchors.centerIn: parent
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}

Text {
anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
text: aPieChart.name
}
}

注意:第12行color:“red”,字符串red会自动转换成QColor类型,其它基础类型也提供了自动转换的功能,如 “640x480”可以转换成QSize.

关于基础类型:​​https://doc.qt.io/qt-6/qtqml-typesystem-basictypes.html​

在main.cpp中使用​​QQuickView​​运行显示app.qml

#include "piechart.h"
#include <QtQuick/QQuickView>
#include <QGuiApplication>

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///app.qml"));
view.show();
return QGuiApplication::exec();
}

关于QGuiApplication: ​​https://doc.qt.io/qt-6/qguiapplication.html​

编译

chapter1-basics.pro内容:

QT += qml quick

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

HEADERS += piechart.h
SOURCES += piechart.cpp \
main.cpp

RESOURCES += chapter1-basics.qrc

DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter1-basics
target.path = $$DESTPATH
INSTALLS += target

QT_INSTALL_EXAMPLES的值是什么??

我在这个文档中找到了相关信息:​​https://doc.qt.io/qt-6/qmake-environment-reference.html​

QT_INSTALL_EXAMPLES - location of examples

作为qt程序员,qmake还是有必要了解一下的:​​https://doc.qt.io/qt-6/qmake-manual.html​

结尾

还有5个部分...