Qt6入门教程 6:Qt元对象系统

目录

一.什么是Qt元对象系统?

[二.编译时Qt Creator偷摸做了哪些事情?](#二.编译时Qt Creator偷摸做了哪些事情?)

1.uic

2.rcc

3.moc


一.什么是Qt元对象系统?

Qt中的元对象系统(Meta-Object System)提供了对象间通信的信号和槽机制、运行时类型信息和动态属性系统。元对象系统是基于以下3个条件的:

●该类必须继承自QObject类;

●必须在类的私有声明区声明Q_OBJECT宏(在类定义时,如果没有指定public或者private,则默认为private);

●元对象编译器Meta-Object Compiler(moc),为QObject的子类实现元对象特性提供必要的代码。

其中,moc工具读取一个C++源文件,如果它发现一个或者多个类的声明中包含有Q_OBJECT宏,便会另外创建一个C++源文件(就是在项目目录中的debug或release目录下看到的以moc开头的C++源文件),其中包含了为每一个类生成的元对象代码。 这些创建的源文件或者被包含进类的源文件中,或者和类的实现同时进行编译和链接。

元对象系统主要是为了实现信号和槽机制才被引入的,不过除了信号和槽机制以外,元对象系统还提供了其他一些特性:

●QObjeCt::metaObject()函数可以返回一个类的元对象,它是QMetaObject类型的对象;

●QMetaObject::className()可以在运行时以字符串形式返回类名,而不需要C++编辑器原生的运行时类型信息(RTTI)的支持;

●QObject::inherits()函数返回一个对象是否是QObject继承树上一个类的实例的信息;

●QObject: :tr()和QObject: :trUtf8()迸行字符串翻译来实现国际化;

●QObject::setProperty()和QObject::property()通过名字来动态设置或者获取对象属性;

●QMetaObject::newlnstance()构造该类的一个新实例。

除了这些特性,还可以使用qobject_cast()函数来对QObject类进行动态类型转换,这个函数的功能类似于标准C++中的dynamic_cast()函数,但它不再需要RTTI的支持。这个函数尝试将它的参数转换为尖括号中的类型的指针,如果是正确的类型,则返回一个非零的指针,如果类型不兼容则返回0。

例如:

cpp 复制代码
QObject *obj = new MyWidget;
QWidget *widget = qobject_cast<QWidget *>(obj);

另外,一个没有定义 Q_OBJECT 宏的类与它最接近的父类是同一类型的。也就是说,如果 A 继承了 QObject 并且定义了 Q_OBJECT,B 继承了 A 但没有定义 Q_OBJECT,C 继承了 B,则 C 的 QMetaObject::className() 函数将返回 A,而不是本身的名字。因此,为了避免这一问题,所有继承了 QObject 的类都应该定义 Q_OBJECT 宏,不管你是不是使用信号槽。

关于元对象系统,详见:Qt Assistant--->The Meta Object System关键字。

信号和槽机制是Qt的核心内容,它依赖于元对象系统,将在下一篇中介绍。

二.编译时Qt Creator偷摸做了哪些事情?

结合前面几篇博文,我们看看编译时Qt Creator偷摸做了哪些事情:

1.uic

User Interface Compiler,它读取Qt Designer创建的XML格式的user interface definition(.ui)文件,生成对应的C++头文件(以ui_为前缀)

.ui文件存在的意义是让界面和业务分离,这样UI设计工程师可以用Qt Designer专心的设计界面,而不用关系业务逻辑。那么.ui文件最后是如何根 C++业务代码关联起来的呢?ui_xxxx.cpp文件中的setupUi函数便是桥梁。

以前面HelloWorld项目中的MainWindow类为例:

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
   // 添加标题栏图标
    setWindowIcon(QIcon(":/icons/AppIcon.ico"));
}
 
MainWindow::~MainWindow()
{
    delete ui;
}

在构造函数中我们调用了ui对象的setupUi方法,并传入MainWindow类的指针;在析构函数中将ui对象删除。

切换到mainwinows.h

cpp 复制代码
#include <QMainWindow>
 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
 
class MainWindow : public QMainWindow
{
  Q_OBJECT
 
public:
  MainWindow(QWidget *parent = nullptr);
  ~MainWindow();
 
private:
  Ui::MainWindow *ui;
};

namespace Ui { class MainWindow; }是前缀声明,这样就可以用Ui::MainWindow声明指针变量ui:

cpp 复制代码
Ui::MainWindow *ui;

而Ui { class MainWindow; }中的MainWindow正是ui_mainwindow.h中Ui_MainWindow类的子类,因此在调用setupUi后,就能用ui访问界面的控件了。

cpp 复制代码
#ifndef UI_MAINWINDOW_H  
#define UI_MAINWINDOW_H  
 
QT_BEGIN_NAMESPACE 
class Ui_MainWindow  
{  
public:  
    // 一些控件对象的声明
    ......
    void setupUi(QMainWindow *MainWindow)  
    {  
         // 一些控件对象的定义
         ......
    } // setupUi  
    ......
};  
 
namespace Ui {  
     class MainWindow: public Ui_MainWindow {};  
} // namespace Ui  
 
QT_END_NAMESPACE  
#endif // UI_MAINWINDOW_H 

2.rcc

Resource Compiler,用于在编译时将资源嵌入到Qt程序中,它读取XML格式的Qt resource(.qrc)文件,生成一个包含资源数据的C++源文件(以qrc_为前缀)

3.moc

Meta-Object Compiler,用于读取一个C++源文件,如果它发现一个或者多个类的声明中包含有Q_OBJECT宏,便会另外创建一个C++源文件(以moc_为前缀)

uic.exe、rcc.exe和moc.exe都在Qt的安装目录中,自己找找吧!

原文链接:Qt6入门教程 6:Qt元对象系统-CSDN博客

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript