前言
众所周知,如果要在 QML使用 C++中定义的类型,有些数据类型是是可以直接使用的,如常见的 int,但是还有一些相对特殊的类型就需要做些特定的操作才可以使用了,那么,这里来看一下如何在 QML 中使用 C++中定义的枚举类型。
正文
1
要将自定义枚举用作数据类型,必须注册其类,并且还必须使用Q_ENUM()声明枚举,以将其注册到Qt的元对象系统。
话不多说,直接上代码:
首先我们定义一个类,继承于 QObject,然后在类中定义一个枚举类型
#include <QObject>
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(Status status READ getStatus WRITE setStatus NOTIFY sigStatusChanged)
public:
explicit Message(QObject *parent = nullptr);
enum Status{
Ready,
Loading,
Finished
};
Q_ENUM(Status)
Status getStatus() const{return m_status;}
void setStatus(Status st){
m_status = st;
emit sigStatusChanged(st);
}
signals:
void sigStatusChanged(Status st);
private:
Status m_status;
};
然后将 Message 类注册成 QML 可使用的类型:
qmlRegisterType<Message>("Message",1,0,"Message");
然后在 QML 中直接进行调用:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Message 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Message{
id:msg
onSigStatusChanged: {
console.log("status = ",st)
}
}
Row{
anchors.centerIn: parent
Button{
text: "Ready"
onClicked: {
console.log("Ready btn clicked")
msg.status = Message.Ready
}
}
Button{
text: "Loading"
onClicked: {
console.log("Loading btn clicked")
msg.status = Message.Loading
}
}
Button{
text: "Finished"
onClicked: {
console.log("Finished btn clicked")
msg.status = Message.Finished
}
}
}
}
为方便演示,我这里定义了三个按钮,点击每个按钮切换可以分别设置 status,然后在 QML 中查看打印信息,看是否为我们想要的结果。
代码跑起来:
输出打印信息:
qml: Ready btn clicked
qml: status = 0
qml: Loading btn clicked
qml: status = 1
qml: Finished btn clicked
qml: status = 2
通过打印信息可以看到,当前 status 已经发生了变化。
以上是最基本的枚举使用方法。
注意:枚举值的名称必须以大写字母开头,以便可以从QML访问。
2
定义枚举时,还有一种写法,如下:
enum class Status{
Ready,
Loading,
Finished
};
Q_ENUM(Status)
就是在枚举名前面加一个class,这叫枚举类,枚举类QML中注册为范围和非范围属性。该Ready值将在Message.Status.Ready和注册Message.Ready。
所以如果这种写法就可以直接在 QML 中通过Message.Status.Ready来调用了。
3
上面说到的枚举类的用途通常是,当有多个枚举定义时,并每个枚举值的名称如果有重复,如 A 枚举中的值是 value1,value2,而枚举 B 里面也包含value1,value2两个值,这时候就需要用到枚举类,要不然会报错。
定义为枚举类后,如果直接通过类名获取枚举值,那么在后面定义的值将会替换前面定义的枚举值。来看个示例:
#include <QObject>
class Message : public QObject
{
Q_OBJECT
public:
explicit Message(QObject *parent = nullptr);
enum class Status{
Ready= 0,
Loading,
Finished
};
enum class StatusTwo{
Ready = 4,
Loading,
Finished
};
Q_ENUM(Status)
Q_ENUM(StatusTwo)
};
这里定义了两个枚举,其枚举成员的名称是一样的,这时候如果直接通过Message.Ready来引用,结果将为4,如下:
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Message{
id:msg
Component.onCompleted: {
console.log("Message.Ready=",Message.Ready)
console.log("Message.Loading=",Message.Loading)
console.log("Message.Finished=",Message.Finished)
console.log("Message.Status.Ready=",Message.Status.Ready)
console.log("Message.Status.Loading=",Message.Status.Loading)
console.log("Message.Status.Finished=",Message.Status.Finished)
console.log("Message.StatusTwo.Ready=",Message.StatusTwo.Ready)
console.log("Message.StatusTwo.Loading=",Message.StatusTwo.Loading)
console.log("Message.StatusTwo.Finished=",Message.StatusTwo.Finished)
}
}
}
输出结果:
qml: Message.Ready= 4
qml: Message.Loading= 5
qml: Message.Finished= 6
qml: Message.Status.Ready= 0
qml: Message.Status.Loading= 1
qml: Message.Status.Finished= 2
qml: Message.StatusTwo.Ready= 4
qml: Message.StatusTwo.Loading= 5
qml: Message.StatusTwo.Finished= 6
结果很明显,只有通过枚举类的方式来调用才能得到正确的值。
4
若想在 QML 中定义信号,并且信号是带枚举类型参数的,那么定义信号的参数可以直接写成 int 类型,如下
Message{
id:msg
signal sigSendStatus(int status)
Component.onCompleted: {
sigSendStatus(Message.Ready)
}
}
OK,关于 QML 中使用 C++定义的枚举类型介绍就到这里。
上述的两份源码在这里