mixing.h
#ifndef MIXING_H
#define MIXING_H
#include
#include
class Mixing : public QObject
{
Q_OBJECT
public:
explicit Mixing(QObject *parent = nullptr);
signals:
void colorChanged(const QColor & color);
public slots: //槽必须被声明为public或protected
void start();
};
#endif // MIXING_H
mixing.cpp
#include "mixing.h"
#include
Mixing::Mixing(QObject *parent) : QObject(parent)
{
}
void Mixing::start()
{
qDebug() << "start";
emit colorChanged(Qt::blue);
}
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
模板参数typename ,即要实现的 C++ 类的类名。
第一个参数uri ,指定一个唯一的包名,一是用来避免名字冲突,二是可以把多个相关类聚合到一个包中方便引用。如我们常写这个语句 “import QtQuick.Controls 2.3” ,其中的 “QtQuick.Controls” 就是包名 uri
而2.3则是版本,是versionMajor=2和versionMinor=3的组合。
qmlName则是 QML中可以使用的类名。
main.cpp
#include
#include
#include
#include "mixing.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
//注册类型 注册动作一定要放在 QML 上下文创建之前,否则的话,注册是没有用的
//Mixing类注册成为Qml类型Mixing,主版本是1,次版本是0,包名是an.qt.Mixing
qmlRegisterType<Mixing>("an.qt.Mixing", 1, 0, "Mixing");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import an.qt.Mixing 1.0
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("mixing")
MouseArea{
anchors.fill: parent
onClicked: {
mixing.start()
}
}
Mixing{
id: mixing
onColorChanged: {
root.color = color
}
}
}
mixing.h
#ifndef MIXING_H
#define MIXING_H
#include
#include
class Mixing : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
public:
explicit Mixing(QObject *parent = nullptr);
enum BALL_COLOR{
BALL_COLOR_YELLOW,
BALL_COLOR_BLUE,
BALL_COLOR_GREEN,
};
signals:
void colorChanged(const QColor & color);
public slots: //槽必须被声明为public或protected
void start(BALL_COLOR ballColor);
};
#endif // MIXING_H
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import an.qt.Mixing 1.0
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("mixing")
MouseArea{ //点击鼠标左键,窗口颜色变蓝;点击鼠标右键,窗口颜色变绿;双击鼠标,窗口颜色变黄
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if(mouse.button === Qt.LeftButton)
{
mixing.start(Mixing.BALL_COLOR_BLUE)
}else if(mouse.button === Qt.RightButton)
{
mixing.start(Mixing.BALL_COLOR_GREEN)
}
}
onDoubleClicked: {
mixing.start(Mixing.BALL_COLOR_GREEN)
}
}
Mixing{
id: mixing
onColorChanged: {
root.color = color
}
}
}
mixing.cpp
#include "mixing.h"
#include
Mixing::Mixing(QObject *parent) : QObject(parent)
{
}
void Mixing::start(BALL_COLOR ballColor)
{
QColor color;
qDebug() << "start";
switch (ballColor) {
case BALL_COLOR_BLUE:
color = Qt::blue;
break;
case BALL_COLOR_GREEN:
color = Qt::green;
break;
case BALL_COLOR_YELLOW:
color = Qt::yellow;
break;
default:
break;
}
emit colorChanged(Qt::blue);
}
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
属性的type、name是必需的,其它是可选项,最常用的有READ、WRITE、NOTIFY。属性的type可以是QVariant支持的任何类型,也可以是自定义类型,包括自定义类、列表类型、组属性等。另外,属性的READ、WRITE、RESET是可以被继承的,也可以是虚函数,这些特性并不常用。
READ:读取属性值,如果没有设置MEMBER的话,它是必需的。一般情况下,函数是个const函数,返回值类型必须是属性本身的类型或这个类型的const引用,没有参数。
WRITE:设置属性值,可选项。函数必须返回void,有且仅有一个参数,参数类型必须是属性本身的类型或这个类型的指针或引用。
NOTIFY:与属性关联的可选信号。这个信号必须在类中声明过,当属性值改变时,就可触发这个信号,可以没有参数,有参数的话只能是一个类型同属性本身类型的参数,用来记录属性改变后的值。
mixing.h
#ifndef MIXING_H
#define MIXING_H
#include
#include
class Mixing : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
//修饰了名为number的属性,number通过Number函数读得数据,通过setNumber函数写入数据,触发信号是Numberchanged函数
Q_PROPERTY(unsigned int number READ Number WRITE setNumber NOTIFY Numberchanged)
public:
explicit Mixing(QObject *parent = nullptr);
enum BALL_COLOR{
BALL_COLOR_YELLOW,
BALL_COLOR_BLUE,
BALL_COLOR_GREEN,
};
unsigned int Number() const;
void setNumber(const unsigned int & Number);
Q_INVOKABLE void stop();
signals:
void colorChanged(const QColor & color);
void Numberchanged();
public slots: //槽必须被声明为public或protected
void start(BALL_COLOR ballColor);
private:
unsigned int m_Number;
};
#endif // MIXING_H
mixing.cpp
#include "mixing.h"
#include
Mixing::Mixing(QObject *parent) : QObject(parent)
{
}
void Mixing::start(BALL_COLOR ballColor)
{
QColor color;
qDebug() << "start";
switch (ballColor) {
case BALL_COLOR_BLUE:
color = Qt::blue;
break;
case BALL_COLOR_GREEN:
color = Qt::green;
break;
case BALL_COLOR_YELLOW:
color = Qt::yellow;
break;
default:
break;
}
emit colorChanged(Qt::blue);
}
unsigned int Mixing::Number() const
{
return m_Number;
}
void Mixing::setNumber(const unsigned int &number)
{
if(number != m_Number)
{
m_Number = number;
emit Numberchanged();
}
}
void Mixing::stop()
{
qDebug() << "颜色改变ing...";
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import an.qt.Mixing 1.0
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("mixing")
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if(mouse.button === Qt.LeftButton)
{
mixing.start(Mixing.BALL_COLOR_BLUE)
}else if(mouse.button === Qt.RightButton)
{
mixing.start(Mixing.BALL_COLOR_GREEN)
}
}
onDoubleClicked: {
mixing.start(Mixing.BALL_COLOR_GREEN)
mixing.number = 10
}
}
Mixing{
id: mixing
onColorChanged: {
root.color = color
mixing.stop(color)
}
Component.onCompleted:
{
console.log("default ball number is ", number)
}
onNumberChanged:
{
console.log("new ball number is ", number)
}
}
}
void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
简单的上下文属性,对应的值为QVariant类型。
void QQmlContext::setContextProperty(const QString &name, QObject *value)
相对来说稍微复杂一些,QObject*对象类型。
main.cpp
#include
#include
#include
#include
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
view.rootContext()->setContextProperty("Data", QString("设置Qml上下文属性"));
view.setSource(QUrl(QStringLiteral("qrc://main.qml")));
view.show();
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Rectangle { //main.cpp已经view.show(),所以不需要在Window对象下定义控件
visible: true
width: 640
height: 480
color: "lightgray"
Text {
id: text
anchors.centerIn: parent
text: Data
}
}
main.cpp
#include
#include
#include
#include
#include "mixing.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
Mixing mixing;
QQuickView view;
view.rootContext()->setContextProperty("mixing", &mixing);
view.setSource(QUrl(QUrl(QStringLiteral("qrc://main.qml"))));
view.show();
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Rectangle {
//main.cpp已经view.show(),所以不需要Window对象下定义控件
id: root
visible: true
width: 640
height: 480
MouseArea{
anchors.fill: parent
acceptedButtons:Qt.LeftButton | Qt.RightButton;
onClicked: {
mixing.start()
mixing.number = 10
}
}
Connections{
target: mixing
onColorChanged: {
root.color = color
mixing.stop(color)
}
onNumberChanged:{
console.log("new ball number is", mixing.number) // 10
}
}
}
Mixing.cpp修改start函数 以及 Mixing.h的start函数去掉形参
void Mixing::start()
{
//QColor color;
qDebug() << "start";
// switch (ballColor) {
// case BALL_COLOR_BLUE:
// color = Qt::blue;
// break;
// case BALL_COLOR_GREEN:
// color = Qt::green;
// break;
// case BALL_COLOR_YELLOW:
// color = Qt::yellow;
// break;
// default:
// break;
// }
emit colorChanged(Qt::blue);
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import an.qt.Mixing 1.0
Window {
id: root
visible: true
width: 640
height: 480
Rectangle { //
objectName: "rect" //这个值是为了在C++中能够找到这个Rectangle
anchors.fill: parent
}
MouseArea{
anchors.fill: parent
acceptedButtons:Qt.LeftButton | Qt.RightButton;
onClicked: {
mixing.start()
mixing.number = 10
qmlSignal("这是qml文件中的qml信号")
}
}
Mixing{
id:mixing
}
}
main.cpp
#include
#include
#include
#include "mixing.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Mixing>("an.qt.Mixing", 1, 0, "Mixing");
QQmlEngine engine;
QQmlComponent compontext(&engine, QUrl(QStringLiteral("qrc:///main.qml")));
QObject *object = compontext.create();
qDebug() << "width value is " << object->property("width").toInt(); //读取width属性值
object->setProperty("width", 320); //修改width属性值
qDebug() << "height value is " << QQmlProperty::read(object, "height").toInt(); //读取height属性值
QQmlProperty::write(object, "height", 240); //修改height属性值
QObject *rect = object->findChild<QObject*>("rect");
if(rect)
{
//查找名字为rect的孩子组件,如果找到的话就将其颜色设置为橘黄色
rect->setProperty("color", "orange");
}
return app.exec();
}
C++中,使用 QMetaObject::invokeMethod() 可以调用QML中的函数,它 是个静态方法,函数原型:
bool QMetaObject::invokeMethod(QObject * obj, const char * member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) [static]
QGenericArgument Q_ARG(Type, const Type & value)
QGenericReturnArgument Q_RETURN_ARG(Type, Type & value)
信号传递到 C++ :使用 QObject::connect() 可以连接QML中的信号,connect()共有四个重载函数,它们都是静态函数。必须使用SIGNAL()宏来声明信号,SLOT()宏声明槽函数
QObject::disconnect() 可以解除信号与槽函数的连接
main.qml 添加一个方法和信号
import QtQuick 2.9
import QtQuick.Window 2.2
import an.qt.Mixing 1.0
Window {
id: root
visible: true
width: 640
height: 480
signal qmlSignal (string message) //单击会输出message的值
onQmlSignal: console.log("这是一个信号:", message)
function qmlFunction(parameter)
{
console.log("这是一个方法", parameter)
return "function from qml"
}
Rectangle {
objectName: "rect" //这个值是为了在C++中能够找到这个Rectangle
anchors.fill: parent
}
MouseArea{
anchors.fill: parent
acceptedButtons:Qt.LeftButton | Qt.RightButton;
onClicked: {
mixing.start()
mixing.number = 10
qmlSignal("这是qml文件中的qml信号")
}
}
Mixing{
id:mixing
}
}
main.cpp 调用信号和方法
#include
#include
#include
#include "mixing.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Mixing>("an.qt.Mixing", 1, 0, "Mixing");
QQmlEngine engine;
QQmlComponent compontext(&engine, QUrl(QStringLiteral("qrc:///main.qml")));
QObject *object = compontext.create();
qDebug() << "width value is " << object->property("width").toInt(); //读取width属性值
object->setProperty("width", 320); //修改width属性值
qDebug() << "height value is " << QQmlProperty::read(object, "height").toInt(); //读取height属性值
QQmlProperty::write(object, "height", 240); //修改height属性值
QObject *rect = object->findChild<QObject*>("rect");
if(rect)
{
//查找名字为rect的孩子组件,如果找到的话就将其颜色设置为橘黄色
rect->setProperty("color", "orange");
}
QVariant returnedValue, message = "Hello from c++";
QMetaObject::invokeMethod(object, "qmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, message));
qDebug() << "returnedValue is " << returnedValue.toString();
Mixing mixing;
QObject::connect(object, SIGNAL(qmlSignal(QString)),
&mixing, SLOT(cppSlot(QString)));
return app.exec();
}
mixing.h中定义cppSlot槽函数
public slots: //槽必须被声明为public或protected
void start();
void cppSlot(const QString &message)
{
qDebug() << "这是一个qml信号:" << message;
}