做58同城網(wǎng)站需要多少錢企業(yè)網(wǎng)站seo排名優(yōu)化
Qt元對(duì)象系統(tǒng)(QMetaObject)
Qt 的元對(duì)象系統(tǒng)叫 Meta-Object-System,提供了對(duì)象之間通信的信號(hào)與槽機(jī)制、運(yùn)行時(shí)類型信息和動(dòng)態(tài)屬性系統(tǒng)。即使編譯器不支持RTTI(RTTI的實(shí)現(xiàn)耗費(fèi)了很大的時(shí)間和存儲(chǔ)空間,這就會(huì)降低程序的性能),我們也能動(dòng)態(tài)獲取類型信息。
元對(duì)象實(shí)質(zhì)上是對(duì)類的描述
但是,元對(duì)象是基于三個(gè)條件的:
?1、該類必須繼承自QObject類
?2、必須在類的私有聲明區(qū)聲明Q_OBJECT宏(在類定義的時(shí)候,如果沒(méi)有指定public,
則默認(rèn)為private,用來(lái)啟用元對(duì)象功能,比如動(dòng)態(tài)屬性、信號(hào)和槽)。
?3、 元對(duì)象編譯器Meta-Object Compiler(moc)為 QObject的子類實(shí)現(xiàn)元對(duì)象
特性提供必要的代碼。
有了元對(duì)象系統(tǒng)后,我們就可以使用Qt的信號(hào)和槽了。
moc(Meta-Object Compiler)元對(duì)象預(yù)編譯器。
moc讀取一個(gè)c++頭文件。如果它找到包含Q_OBJECT宏的一個(gè)或多個(gè)類聲明,它會(huì)生成一個(gè)包含這些類的元對(duì)象代碼的c++源文件,并且以moc_作為前綴。
信號(hào)和槽機(jī)制、運(yùn)行時(shí)類型信息和動(dòng)態(tài)屬性系統(tǒng)需要元對(duì)象代碼。
由moc生成的c++源文件必須編譯并與類的實(shí)現(xiàn)聯(lián)系起來(lái)。通常,moc不是手工調(diào)用的,而是由構(gòu)建系統(tǒng)自動(dòng)調(diào)用的。
獲取類關(guān)聯(lián)的元對(duì)象的函數(shù)是:metaObject
QMetaObject ?*mtobj = QObject::metaObject()
如:
QPushButton *btn=new QPushButton();
const QMetaObject *metaPtr=btn->metaObject(); ???????//獲取元對(duì)象指針
常用的函數(shù):
(1)函數(shù)QMetaObject::className():該函數(shù)運(yùn)行時(shí)返回類名稱的字符串
(2)函數(shù)QObjetc::inhetits()??梢耘袛嘁粋€(gè)對(duì)象是不是繼承自某個(gè)類的實(shí)例。頂層的父類是QObject ;
(3)函數(shù)QMetaObject::superClass()。用來(lái)返回該元對(duì)象所描述類的父類的元對(duì)象,通過(guò)父類的元對(duì)象可以獲取父類的一些元數(shù)據(jù);
(4)函數(shù)qobject_cast(): 對(duì)于Object及其子類對(duì)象,可以使用函數(shù)qobject_cast()進(jìn)行動(dòng)態(tài)類型轉(zhuǎn)換,此處可以理解為c++中的強(qiáng)制類型轉(zhuǎn)換
屬性系統(tǒng)(Q_PROPERTY)
在QObject的子類中,使用宏Q_PROPERTY定義屬性
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])
Q_PROPERTY()宏定義一個(gè)返回值類型為type,名稱為name的屬性。屬性的類型可以是QVarient支持的任何類型(?C++標(biāo)準(zhǔn)類型、類名、結(jié)構(gòu)體、枚舉等),也可以用戶自定義類型。
READ:用于讀取屬性值。
WRITE:寫(xiě)訪問(wèn)器函數(shù)是可選的。用于設(shè)置屬性值。它必須返回void,并且必須只接受一個(gè)參數(shù),要么是屬性的類型,要么是指向該類型的指針或引用。
MEMBER:如果未指定讀取訪問(wèn)器函數(shù),則需要成員變量關(guān)聯(lián)。這使得給定的成員變量可讀寫(xiě),而無(wú)需創(chuàng)建讀寫(xiě)訪問(wèn)器函數(shù)。使用MEMBER可以替代READ、WRITE。
RESET:復(fù)位功能是可選的。它用于將屬性設(shè)置回其特定于上下文的默認(rèn)值。
NOTIFY:通知信號(hào)是可選的。如果已定義,它應(yīng)該指定該類中的一個(gè)現(xiàn)有信號(hào),該信號(hào)在屬性值更改時(shí)發(fā)出。
定義屬性:
頭文件:#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定義的類int getvalue() const;void setvalue(const int& value);CTest gettest() const;void settest(const CTest& test);signals:void valueChanged(int value);void testChanged(CTest test);private:int m_value;CTest m_test;};#endif // COLORMAKER_H源文件#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}int ColorMaker::getvalue() const{return m_value;}void ColorMaker::setvalue(const int &value){m_value = value;emit valueChanged(m_value);}CTest ColorMaker::gettest() const{return m_test;}void ColorMaker::settest(const CTest &test){m_test = test;emit testChanged(m_test);}
使用屬性:
屬性的讀寫(xiě)既可以使用各個(gè)屬性自己的讀寫(xiě)函數(shù),也可以使用屬性通用的函數(shù):setProperty() 寫(xiě)屬性,property() 讀屬性,都是通過(guò)屬性的名稱來(lái)尋找特定屬性實(shí)現(xiàn)讀寫(xiě)。
bool setProperty(const char *name, const QVariant &value);
QVariant property(const char *name) const;
setProperty() 第一個(gè)參數(shù)是普通字符串,就是屬性的名稱,第二個(gè)參數(shù)是屬性的數(shù)值。QVariant 是 Qt 定義的通用變量類型,標(biāo)準(zhǔn) C++ 的類型和 Qt 自己的數(shù)值類型都可以自動(dòng)轉(zhuǎn)為 QVariant 類的對(duì)象。
int propertyCount() const;?通過(guò)元對(duì)象獲取屬性的個(gè)數(shù)
QMetaProperty property(int index) const;?獲取屬性
QMetaProperty 的const char *name() const;?獲取屬性名
例子:
#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include "ColorMaker.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void recv(int nval);void recvtest(CTest test);private:Ui::Widget *ui;};#endif // WIDGET_H源文件#include "widget.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);ColorMaker *cm = new ColorMaker();connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);cm->setvalue(1);int value = cm->getvalue();cm->setProperty("value", 2);value = cm->property("value").toInt();CTest test;test.nAge = 2;test.strName = "qq";cm->setProperty("test",QVariant::fromValue(test));CTest test1 = qvariant_cast<CTest>(cm->property("test"));QObject *object ?= cm;const QMetaObject *metaobject = object->metaObject();int ncount = metaobject->propertyCount();for (int i = 0; i < ncount; ++i){QMetaProperty metaproperty = metaobject->property(i);const char *name = metaproperty.name();qDebug() << name;QVariant value = object->property(name);qDebug() << value;}CTest s;s.nAge = 1;s.strName = "hello";QVariant varTest;varTest.setValue(s);QVariant var = QVariant::fromValue(s);bool b = var.canConvert<CTest>();if(b){CTest test = var.value<CTest>();CTest test1 = qvariant_cast<CTest>(var);qDebug() << test.nAge;qDebug() << test.strName;}}Widget::~Widget(){delete ui;}void Widget::recv(int nval){int a = nval;qDebug() << a;}void Widget::recvtest(CTest test){qDebug() << test.nAge;qDebug() << test.strName;}
作用:
- 屬性系統(tǒng)提供了可以像操作普通的數(shù)據(jù)成員一樣操作這些自定義屬性的方法,同時(shí)也可以利用Qt的信號(hào)槽系統(tǒng)來(lái)監(jiān)聽(tīng)屬性值的變化。
使用場(chǎng)景:
- Q_PROPERTY用于c++類注冊(cè)到qml交互上。在c++的變化發(fā)送信號(hào),而在qml上接收信號(hào),實(shí)現(xiàn)處理槽函數(shù)。這個(gè)使用于qml導(dǎo)出到c++類,c++類獲取和設(shè)置qml的屬性。
- 自定義qt designer 插件 在ui上可以直接看到并設(shè)置屬性值、信號(hào)槽。
延伸:
Q_DECLARE_METATYPE
Q_DECLARE_METATYPE(Type)向Qt元系統(tǒng)注冊(cè)一些非基本類型。Type可以是自定義類、結(jié)構(gòu)體、枚舉。一旦注冊(cè)后,在Qt元系統(tǒng)中就可以很方便的利用這些非基本類型。
如果Type在命名空間中,Q_DECLARE_METATYPE()必須在命名空間外部。
定義:
class CTest
{
public:
????CTest(){}
????int nAge;
????QString strName;
};
//或者
//struct CTest
//{
// ???int nAge;
// ???QString strName;
//};
Q_DECLARE_METATYPE(CTest)
使用:
設(shè)置函數(shù)
QVariant::setValue或者 QVariant fromValue
獲取函數(shù)
Value 或者 QVariant fromValue
???CTest s;
???s.nAge = 1;
???s.strName = "hello";
???QVariant varTest;
???varTest.setValue(s);
???QVariant var = QVariant::fromValue(s);
???bool b = var.canConvert<CTest>();
???if(b)
???{
???????CTest test = var.value<CTest>();
???????CTest test1 = qvariant_cast<CTest>(var);
???????qDebug() << test.nAge;
???????qDebug() << test.strName;
???}
枚舉常用宏
?Q_ENUM
作用:宏Q_ENUM會(huì)向元對(duì)象系統(tǒng)注冊(cè)一個(gè)枚舉類型。
使用注意事項(xiàng):
1.使用Q_ENUM之前,必須在類中先聲明Q_OBJECT或Q_GADGET宏。
2.Q_ENUM(枚舉類型)必須放在枚舉聲明之后,放在前面編譯器會(huì)報(bào)錯(cuò)。
如注冊(cè)O(shè)rientation枚舉
class Widget : public QWidget
{
????Q_OBJECT
public:
????Widget(QWidget *parent = nullptr);
????~Widget();
????enum Orientation {
????????Up = 1,
????????Down = 2,
????????Left = 3,
????????Right = 4
????};
????Q_ENUM(Orientation) ?//向元對(duì)象系統(tǒng)注冊(cè)枚舉類型
public slots:
????void recv(int nval);
????void recvtest(CTest test);
private:
????Ui::Widget *ui;
};
使用靜態(tài)函數(shù)QMetaEnum::fromType()來(lái)獲取QMetaEnum
QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //MyEnum是當(dāng)前類,Orientation是枚舉的類型
????QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); ?//通過(guò)靜態(tài)函數(shù)fromType獲取QMetaEnum對(duì)象
????QString name = metaEnum.name(); ??????????????????//枚舉名稱
????int count = metaEnum.keyCount(); ?????????????????//枚舉數(shù)量
????QString keyIndex = metaEnum.key(0); ??????????????//下標(biāo)為0的key
????int valueIndex = metaEnum.value(0); ??????????????//下標(biāo)為0的value
????QString Key = metaEnum.valueToKey(Widget::Left); ?//通過(guò)value得到key
????int value = metaEnum.keyToValue("Left"); ?????????//通過(guò)key得到value
????qDebug() << "枚舉的名稱:" << name;
????qDebug() << "枚舉的數(shù)量:" << QString::number(count);
????qDebug() << "index下標(biāo)的key值:" << keyIndex;
????qDebug() << "index下標(biāo)的Value值:" << QString::number(valueIndex); ???????????????????????????????????????????????????????????????????????qDebug() << "value對(duì)應(yīng)的key值:" << Key;
????qDebug() << "key值對(duì)應(yīng)的Vaule:" << QString::number(value);
Q_FLAG
為了解決枚舉變量的組合使用,增加枚舉變量間與或非計(jì)算。且運(yùn)算結(jié)果還是一個(gè)QFlags包裝的枚舉量。一個(gè)普通的枚舉類型包裝成QFlags型,需要使用Q_DECLARE_FLAGS宏,在全局任意地方使用”|"操作符計(jì)算自定義的枚舉量,需要使用Q_DECLARE_OPERATORS_FOR_FLAGS宏。
Q_DECLARE_FLAGS()宏
Q_DECLARE_FLAGS(Flags, Enum)宏展開(kāi)為 typedef QFlags<Enum> ?Flags;
QFlags<Enum>是一個(gè)模板類,其中Enum是枚舉類型,QFlags用于存儲(chǔ)枚舉值的組合
Q_DECLARE_OPERATORS_FOR_FLAGS()宏
1.Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)賦予了Flags一個(gè)全局操作符“|”,沒(méi)有這個(gè)宏語(yǔ)句,Flags量之間進(jìn)行與操作后的結(jié)果將是一個(gè)int值,而不是Flags值。
2.Q_DECLARE_OPERATORS_FOR_FLAGS必須定義在類外。
3.Q_DECLARE_OPERATORS_FOR_FLAGS只提供了“或”操作,沒(méi)有提供“與”“非”操作。
例子
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "ColorMaker.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
????Q_OBJECT
public:
????Widget(QWidget *parent = nullptr);
????~Widget();
????enum Orientation {
????????Up = 1,
????????Down = 2,
????????Left = 4,
????????Right = 8
????};
????Q_ENUM(Orientation) ?//向元對(duì)象系統(tǒng)注冊(cè)枚舉類型
????Q_DECLARE_FLAGS(OrientationFlag,Orientation)
????Q_FLAG(OrientationFlag)
public slots:
????void recv(int nval);
????void recvtest(CTest test);
private:
????Ui::Widget *ui;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)
#endif // WIDGET_H
使用
????QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); ?//通過(guò)靜態(tài)函數(shù)fromType獲取QMetaEnum對(duì)象
????QString name = metaEnum.name(); ??????????????????//枚舉名稱
????int count = metaEnum.keyCount(); ?????????????????//枚舉數(shù)量
????QString keyIndex = metaEnum.key(0); ??????????????//下標(biāo)為0的key
????int valueIndex = metaEnum.value(0); ??????????????//下標(biāo)為0的value
????QString Key = metaEnum.valueToKey(Widget::Left); ?//通過(guò)value得到key
????int value = metaEnum.keyToValue("Left"); ?????????//通過(guò)key得到value
????QString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right); //通過(guò)value得到key
????int value2 = metaEnum.keysToValue("Up | Down");
????qDebug() << "枚舉的名稱:" << name;
????qDebug() << "枚舉的數(shù)量:" << QString::number(count);
????qDebug() << "index下標(biāo)的key值:" << keyIndex; ?//Up
????qDebug() << "index下標(biāo)的Value值:" << QString::number(valueIndex); ?//1
????qDebug() << "value對(duì)應(yīng)的key值:" << Key; //Left
????qDebug() << "value對(duì)應(yīng)的key值:" << Key2; //Left|Right
????qDebug() <<"key值對(duì)應(yīng)的Vaule:"<< QString::number(value);//4
qDebug() <<"key值對(duì)應(yīng)的Vaule:"<< QString::number(value2);//3
QMetaObject::invokeMethod()
作用:使用QMetaObject::invokeMethod()調(diào)用QObject的某個(gè)注冊(cè)到元對(duì)象系統(tǒng)中的方法。支持跨線程調(diào)用。
一般該方法是信號(hào)、或者槽函數(shù)。無(wú)論這個(gè)方法是公有的、保護(hù)的還是私有的。
如果是普通函數(shù),則需要使用Q_INVOKABLE宏把函數(shù)注冊(cè)到元對(duì)象系統(tǒng)。
格式:
bool QMetaObjcet:invokeMethod(
QObject* obj,
const char* member,
Qt::ConnectionType type,
QGenericReturnArgument ret,
QGenericReturnArgument ?vla0 = QGenericReturnArgument(0),
QGenericReturnArgument ?vla1 = QGenericReturnArgument(),
QGenericReturnArgument ?vla2 = QGenericReturnArgument(),
QGenericReturnArgument ?vla3 = QGenericReturnArgument(),
QGenericReturnArgument ?vla4 = QGenericReturnArgument(),
QGenericReturnArgument ?vla5 = QGenericReturnArgument(),
QGenericReturnArgument ?vla6 = QGenericReturnArgument(),
QGenericReturnArgument ?vla7 = QGenericReturnArgument(),
QGenericReturnArgument ?vla8 = QGenericReturnArgument(),
QGenericReturnArgument ?vla9 = QGenericReturnArgument());
返回值:返回true說(shuō)明調(diào)用成功;返回false,要么是因?yàn)闆](méi)有你說(shuō)的那個(gè)方法,要么是參數(shù)類型不匹配;
obj:被調(diào)用對(duì)象的指針;
member:方法名字 ??必須是信號(hào)、槽,以及Qt元對(duì)象系統(tǒng)能識(shí)別的類型, 如果不是信號(hào)和槽,可以使用qRegisterMetaType()來(lái)注冊(cè)數(shù)據(jù)類型。此外,使用Q_INVOKABLE來(lái)聲明函數(shù),也可以正確調(diào)用。
type:連接類型;invokeMethod為信號(hào)槽而生,你可以指定連接類型,如果被調(diào)用的對(duì)象和發(fā)起調(diào)用的線程是同一線程,那么可以使用Qt::DirectConnection、Qt::AutoConnection、Qt::QueuedConnection,如果被調(diào)用對(duì)象在另一個(gè)線程,那么建議使用Qt::QueuedConnection;
ret:接收返回值;
然后就是多達(dá)10個(gè)可以傳遞給被調(diào)用方法的參數(shù);(看來(lái)信號(hào)槽的參數(shù)個(gè)數(shù)是有限制的,最好不要超過(guò)10個(gè))
QGenericArgument和QGenericReturnArgument是內(nèi)部幫助程序類,由于可以動(dòng)態(tài)調(diào)用信號(hào)和槽,因此必須使用Q_ARG()和Q_RETURN_ARG()宏來(lái)封裝參數(shù)
注意:此功能是線程安全的。
例子:
#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();private slots:QString testslot(int n);};#endif // COLORMAKER_H#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}QString ColorMaker::testslot(int n){return "q";}調(diào)用#include "widget.h"//#include "qobjectdefs.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>#include <QMetaObject>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);ColorMaker *cm = new ColorMaker();QString retVal;QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));}void Widget::test(){int a = 1;}
Q_INVOKABLE
作用:定義一個(gè)類的成員函數(shù)時(shí)使用Q_INVOKABLE宏來(lái)修飾,就可以讓該方法被元對(duì)象系統(tǒng)調(diào)用(即把該函數(shù)注冊(cè)到元對(duì)象系統(tǒng))。
注意事項(xiàng):Q_INVOKABLE宏必須放在返回類型前面。
如
private :
Q_INVOKABLE??QString testmd(int n);
QString ColorMaker::testmd(int n)
{
????return "md";
}
使用場(chǎng)景:
- c++和qml混用.
普通類成員函數(shù)是不能直接在qml使用。除非是聲明為槽函數(shù)或者用Q_INVOKABLE聲明函數(shù).
- 和QMetaObject::invokeMethod()結(jié)合使用,invokeMethod函數(shù)的參數(shù)member方法如果是自定義的普通函數(shù),需使用Q_INVOKABLE宏注冊(cè)到元對(duì)象系統(tǒng)。
例子
class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();private :Q_INVOKABLE ?QString testmd(int n);};ColorMaker *cm = new ColorMaker();QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));
完整代碼:
#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定義的類int getvalue() const;void setvalue(const int& value);CTest gettest() const;void settest(const CTest& test);signals:void valueChanged(int value);void testChanged(CTest test);private slots:QString testslot(int n);private :Q_INVOKABLE ?QString testmd(int n);private:int m_value;CTest m_test;};#endif // COLORMAKER_H#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}int ColorMaker::getvalue() const{return m_value;}void ColorMaker::setvalue(const int &value){m_value = value;emit valueChanged(m_value);}CTest ColorMaker::gettest() const{return m_test;}void ColorMaker::settest(const CTest &test){m_test = test;emit testChanged(m_test);}QString ColorMaker::testslot(int n){return "q";}QString ColorMaker::testmd(int n){return "md";}#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include "ColorMaker.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();enum Orientation {Up = 1,Down = 2,Left = 4,Right = 8};Q_ENUM(Orientation) ?//向元對(duì)象系統(tǒng)注冊(cè)枚舉類型Q_DECLARE_FLAGS(OrientationFlag,Orientation)Q_FLAG(OrientationFlag)public slots:void recv(int nval);void recvtest(CTest test);public slots:void test();private:Ui::Widget *ui;};Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)#endif // WIDGET_H#include "widget.h"//#include "qobjectdefs.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>#include <QMetaObject>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); ?//通過(guò)靜態(tài)函數(shù)fromType獲取QMetaEnum對(duì)象QString name = metaEnum.name(); ??????????????????//枚舉名稱int count = metaEnum.keyCount(); ?????????????????//枚舉數(shù)量QString keyIndex = metaEnum.key(0); ??????????????//下標(biāo)為0的keyint valueIndex = metaEnum.value(0); ??????????????//下標(biāo)為0的valueQString Key = metaEnum.valueToKey(Widget::Left); ?//通過(guò)value得到keyint value = metaEnum.keyToValue("Left"); ?????????//通過(guò)key得到valueQString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right); ?//通過(guò)value得到keyint value2 = metaEnum.keysToValue("Up | Down");qDebug() << "枚舉的名稱:" << name;qDebug() << "枚舉的數(shù)量:" << QString::number(count);qDebug() << "index下標(biāo)的key值:" << keyIndex; ?//UpqDebug() << "index下標(biāo)的Value值:" << QString::number(valueIndex); ?//1qDebug() << "value對(duì)應(yīng)的key值:" << Key; //LeftqDebug() << "value對(duì)應(yīng)的key值:" << Key2; //Left|RightqDebug() <<"key值對(duì)應(yīng)的Vaule:"<< QString::number(value);//4qDebug() <<"key值對(duì)應(yīng)的Vaule:"<< QString::number(value2);//3ColorMaker *cm = new ColorMaker();QObject *object ?= cm;connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);QString retVal;QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));cm->setvalue(1);int value1 = cm->getvalue();cm->setProperty("value", 2);value = cm->property("value").toInt();CTest test;test.nAge = 2;test.strName = "qq";cm->setProperty("test",QVariant::fromValue(test));CTest test1 = qvariant_cast<CTest>(cm->property("test"));const QMetaObject *metaobject = object->metaObject();int ncount = metaobject->propertyCount();for (int i = 0; i < ncount; ++i){QMetaProperty metaproperty = metaobject->property(i);const char *name = metaproperty.name();qDebug() << name;QVariant value = object->property(name);qDebug() << value;}CTest s;s.nAge = 1;s.strName = "hello";QVariant varTest;varTest.setValue(s);QVariant var = QVariant::fromValue(s);bool b = var.canConvert<CTest>();if(b){CTest test = var.value<CTest>();CTest test1 = qvariant_cast<CTest>(var);qDebug() << test.nAge;qDebug() << test.strName;}}Widget::~Widget(){delete ui;}void Widget::recv(int nval){int a = nval;qDebug() << a;}void Widget::recvtest(CTest test){qDebug() << test.nAge;qDebug() << test.strName;}void Widget::test(){int a = 1;}