概述
总第41篇
本文主要总结了用Qt框架做项目开发的过程中,类的元对象MetaObject
相关的几个核心知识点,收录于此,以供大家参考,也方便于自己在工作过中可以快速温习回看。
1.元对象系统与反射
反射
是指程序在运行时可以访问、检测和修改其自身状态或行为的一种能力,它和内省(type introspection)
不是同的。内省机制
仅指程序在运行时对自身信息(元数据)的检测,而反射不仅包括有检测能力,还要能根据这些信息来改变程序状态或结构。
Qt的反射是基于元对象系统
的, 对应的类即是QMetaObject
,所有继承自QObject
的类都有元对象,都可以通过这个类的元对象metaObject()
来获取属性、方法、事件等。
这里放一个类的实现例子,以便更好地理解元反射。
class TestObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChange) //Q_PROPERTY 注册成员变量
Q_PROPERTY(QString text MEMBER m_text NOTIFY textChange) //AAA.注册的成员变量能够响应自定义的signals textChange
public:
TestObject(QObject* parent);
~TestObject();
void init();
Q_INVOKABLE QString text(); //注册类的成员函数
Q_INVOKABLE void setText(const QString& strText);
QString m_text; //类的成员变量
signals:
void textChange(); //自定义的signals
public slots:
void textslot(){qDebug()<<"欢迎关注知乎:武三郎"<<endl;} //自定义的signals响应的槽函数
};
//=========cpp文件============
TestObject::TestObject(QObject* parent) : QObject (parent)
{
this->setObjectName("TestObject");
connect(this, SIGNAL(textChange()),this, SLOT(textslot()));
}
TestObject::~TestObject()
{
}
void TestObject::init()
{
qDebug()<<"init"<<endl;
}
QString TestObject::text()
{
return m_text;
}
void TestObject::setText(const QString& strText)
{
if (m_text == strText)
return;
m_text = strText;
// emit textChange(); //有了AAA那一行,这一句不需要了
}
下面是对上面类的调用方式:
TestObject* obj = new TestObject(this);
qDebug()<<obj->objectName()<<endl; //输出对象的名字
obj->setProperty("text", "hahaha"); //设置对象的属性
qDebug()<<obj->property("text").toString()<<endl; //输出对象的属性
//得到注册的类成员函数
const QMetaObject* mobj = obj->metaObject();
qDebug()<<mobj->methodCount()<<endl;
for(int i = 0; i < mobj->methodCount(); i++)
{
QMetaMethod mMethod = mobj->method(i);
QByteArray byteArray = mMethod.name();
//输出函数类型与函数名称
qDebug()<<mMethod.typeName()<<"->"<<QString(byteArray)<<endl;
}
//调用注册的成员函数,通过Q_RETURN_ARG来获取返回值
qDebug()<<"begin QMetaObject::invokeMethod"<<endl;
QString invokeString;
//调用类的成员函数
QMetaObject::invokeMethod(obj, "text", Qt::DirectConnection, Q_RETURN_ARG(QString, invokeString));
qDebug()<<invokeString<<endl;
// 再次设置text值,可以响应信号
obj->setProperty("text", "luelueluelue");
从上面的代码中可以看出,我们可以随时获取当前类的成员变量及成员函数,这就是反射。Qt框架让C++这种静态语言有了动态的特性,这就是其强大之处。
2.元对象获取属性的方法
这里以QPushButton
为例来加以说明。其示例代码如下:
QPushButton *btn = new QPushButton;
const QMetaObject *metaobject = btn->metaObject(); //获取元对象
int count = metaobject->propertyCount(); //获取属性的总数量
for (int i = 0; i < count; ++i)
{
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
QVariant value = btn->property(name);
qDebug() << name << value;
}
//其输出信息如下:
objectName QVariant(QString, "")
modal QVariant(bool, false)
windowModality QVariant(int, 0)
enabled QVariant(bool, true)
geometry QVariant(QRect, QRect(0,0 640x480))
frameGeometry QVariant(QRect, QRect(0,0 639x479))
normalGeometry QVariant(QRect, QRect(0,0 0x0))
......
从打印的信息可以看出,父类(superClass)的很多属性也获取到了,如果我们想只获取当前类的属性信息呢,如何做?这时只要将代码修改成如下形式即可:
QPushButton *btn = new QPushButton;
const QMetaObject *metaobject = btn->metaObject();
int count = metaobject->propertyCount();
int index = metaobject->propertyOffset(); //获取属性偏移
for (int i = index; i < count; ++i)
{
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
QVariant value = btn->property(name);
qDebug() << name << value;
}
其它的属性获取方式也是类似的,在QMetaObject
中提供了众多的接口,可以参考接口函数进行获取。
3.项目开发中的几点经验
- 多线程编译
若你使用Qt Creator
作为IDE
开发环境,那么,你可以在项目的构建套件中设置MAKEFLAGS = -j8
, 从而启动多线程编译,节省程序编译时间。具体的设置方法如下图所示:
- 可以在
pro
文件中标记版本号和ico
图标
可以用下面的代码方式在pro
文件中标记,方便简单。
VERSION = V1.23.09.88
Win32:RC_ICONS = appIcon.ico
- 移除和重置样式
移除旧的样式可用如下代码:style()->unpolish(ui->btn);
重置新的样式可用如下代码:style()->polish(ui->btn);
- Qt提供了内置图标,封装在
QStyle
中
在QStyle::StandardPixmap
这个枚举变量中存储了70多个内置图标,可以直接在程序中调用,非常方便。
- 根据系统位数加载程序
在程序中,可以用代码设置根据系统的位数不同来加载不同的程序,其代码示例如下:
win32 {
if contains(DEFINES, WIN64)
{
DESTDIR = $${PWD}/../../bin64
}
else
{
DESTDIR = $${PWD}/../../bin32
}
}
- 用
findChildren
查找所有子控件
可以灵活地用findChildren()
函数查找该控件下的所有子控件,findChild()
是查找单个控件。其示例代码如下:
//查找指定类名objectName的控件
QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("CurrentWidget");
//查找所有QLineEdit
QList<QLineEdit *> allEdits = parentWidget.findChildren<QLineEdit *>();
//只查找一级子控件,不递归
QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
- 用
inherits()
函数判断所属关系
在写程序的过程中,可以巧妙地使用inherits()
函数来判断某个类是否属于某个类。例如:
QTimer *timer = new QTimer; // QTimer inherits QObject
timer->inherits("QTimer"); // returns true
timer->inherits("QObject"); // returns true
timer->inherits("QAbstractButton"); // returns false
- 调试
当在程序调试时,若遇到很多错误,一定要从第一个错误开始,一个一个地解决,不要急着去看下面的错误,可能后面的很多错误都是由第一个错误导致的,第一个错误解决了,后面的错误也就消失了。
本文到此结束!
如果对你有帮助,请随手 点赞 或 点喜欢!
=======================================================
欢迎【关注、私信 @武三郎】。我们一起交流一起进步。
最后
以上就是拉长康乃馨为你收集整理的qt多线程访问同一变量_Qt开发中的几点关键经验及类的元对象反射问题,值得收藏参考...的全部内容,希望文章能够帮你解决qt多线程访问同一变量_Qt开发中的几点关键经验及类的元对象反射问题,值得收藏参考...所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复