Qt是如何在C++基础上扩展的

26 篇文章 3 订阅

写在前面

Qt 是一个建立在 C++ 之上的框架,它扩展了 C++ 的功能,使得开发者可以更容易地开发跨平台的应用程序。Qt 的设计哲学和功能集都与 C++ 紧密相关,但同时也提供了比纯 C++ 更高的生产力和更丰富的功能。

Qt如何在C++基础上扩展的

这里新建一个C++项目和QWidget项目比较。

自动生成的文件及代码比较:
1
属性页比较:
2
可以看到创建的Qt项目比标准C++项目多了了几行代码,多了几个Qt相关的配置。

多出的代码如下:

QApplication a(argc, argv);    //创建一个唯一的QApplication对象
QObjectTest w;                //创建了一个QWidget对象
w.show();                    //显示QWidget对象
return a.exec();            //进入唯一的QApplication对象的消息循环

可以看到创建Qt项目时,会自动创建一个QApplication对象和一个窗体对象,然后显示这个窗体并进入桌面应用都必须要有的消息循环。

Qt项目多出的配置如下:
3
可以看到多出的配置有:

Qt Project Settings(同.pro文件),Qt项目相关配置

Qt Meta-Object Complier: Qt元对象编译器moc,用来编译所有带Q_OBJECT宏的类所属的源文件。

Qt Resource Complier: Qt资源对象编译器rcc,用来编译Qt资源文件.qrc。这里还包含了Qt Quick Complier编译器,用来编译QML,这里以QWidget为主,不作讨论。

Qt User Interface Complier: Qt用户界面编译器uic,用来编译用户界面文件.ui。

这几个编译器是何时作用的,这里编译项目看编译输出:
4
至此可以知道Qt在C++项目的编译编译流程中添加了uic、rcc、moc等编译器的编译,如图:
5
6

普通C++类使用Qt核心特性

要想使普通C++类附带Qt的核心特性,需满足:

①必须在Qt开发环境(即Qt项目)中

②使该类继承QObject

③声明Q_OBJECT宏

这里创建一个C++类CppTest:
7
重新生成,可以看到直接到编译步骤,未涉及Qt相关的编译:
8

添加QObject类继承以及Q_OBJECT宏后,重新编译:
9
注意:继承QObject、添加Q_OBJECT宏缺一不可!!!

单独继承QObject而不声明Q_OBJECT宏,不会进入Qt相关编译流程:
10
单独声明Q_OBJECT宏,而不继承Q_Object,编译报错:
11
C++类继承QObject并添加Q_OBJECT宏后,就可以在该类中使用Qt的动态属性、GUI、信号和槽、模型/视图、插件、绘图、动画等核心特性了。

标准C++项目无法直接转成Qt项目

无法在VS中通过配置设置添加Qt环境!!!
无法在VS中通过配置设置添加Qt环境!!!
无法在VS中通过配置设置添加Qt环境!!!

即属性中只能添加Qt相关的头文件和库,无法改变当前项目的编译过程(无法添加moc元对象编译器、uic用户界面文件编译器、qrc资源文件编译器及相应的配置选项)。
12
13

QObject提供的一些扩展应用

动态属性

Qt的动态属性(Dynamic Properties)允许开发者在运行时为对象添加额外的属性,这些属性并不需要在对象的类定义中预先声明。动态属性的机制使得Qt的QObject派生类能够具有更加灵活的属性管理方式,它们可以用于存储配置信息、用户偏好设置、状态信息等。

以下是使用Qt动态属性的一些关键点:

  1. 注册属性: 使用Q_CLASSINFO宏在类定义中注册动态属性的名称。这步是可选的,主要用于为属性提供元数据。
Q_CLASSINFO("dynamicPropertyName", "defaultValue")
  1. 设置属性**: 使用QObject::setProperty()方法为对象设置动态属性。
myObject.setProperty("dynamicPropertyName", QVariant(value));
  1. 获取属性: 使用QObject::property()方法获取对象的动态属性。
QVariant value = myObject.property("dynamicPropertyName");
  1. 监听属性变化: 可以通过连接QObject::propertyChanged()信号来监听动态属性的变化。
connect(&myObject, &QObject::propertyChanged, this, &MyClass::onPropertyChanged);
  1. 删除属性**: 使用QObject::setProperty()方法并传入nullptr作为值,可以删除动态属性。
myObject.setProperty("dynamicPropertyName", QVariant());
  1. 属性的类型**: 动态属性的值通常是QVariant类型,这意味着它可以存储多种类型的数据。
  2. 动态属性的作用域**: 动态属性是与对象实例绑定的,它们不是类级别的,也不是静态的。
  3. 使用场景**: 动态属性适用于需要在运行时添加或修改属性的场景,例如插件架构、脚本绑定、用户配置等。

下面是一个简单的示例代码,展示了如何在Qt中使用动态属性:

#include <QObject>
#include <QVariant>
#include <QDebug>

class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject(QObject *parent = nullptr) : QObject(parent) {
        // 可以在这里设置默认的动态属性
    }

    void setDynamicProperty(const QString &name, const QVariant &value) {
        setProperty(name.toUtf8().constData(), value);
    }

    QVariant getDynamicProperty(const QString &name) const {
        return property(name.toUtf8().constData());
    }
};

int main() {
    MyObject obj;

    // 设置动态属性
    obj.setDynamicProperty("username", "JohnDoe");
    obj.setDynamicProperty("age", 30);

    // 获取动态属性
    qDebug() << "Username:" << obj.getDynamicProperty("username").toString();
    qDebug() << "Age:" << obj.getDynamicProperty("age").toInt();

    return 0;
}

Q_PROPERTY

在Qt中,Q_PROPERTY宏是一种强大的机制,它允许开发者在Qt类的声明中定义属性,这些属性可以具有读写权限、只读权限或只写权限,并可以指定属性的类型、名称和额外的元数据。使用Q_PROPERTY宏定义的属性可以被Qt的属性系统自动管理,并且可以很方便地与Qt的信号和槽机制、属性绑定、以及序列化等功能集成。

Q_PROPERTY的使用格式如下:

Q_PROPERTY(type name
           READ getFunction
           [WRITE setFunction]
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [REVISION int]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL])

这里的选项可以根据需要进行选择:

  • type和name:属性的类型和名称。
  • READ、WRITE和RESET:用于读取、写入和重置属性的成员函数。
  • NOTIFY:当属性发生变化时,会发出的信号。
  • REVISION、DESIGNABLE、SCRIPTABLE、STORED、USER、CONSTANT和FINAL:一些用于修改属性特性的选项。

下面是一个简单的示例:

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString myProperty READ myProperty WRITE setMyProperty NOTIFY myPropertyChanged)

public:
    MyClass(QObject *parent = nullptr) : QObject(parent) {}

    QString myProperty() const { return m_myProperty; }
    void setMyProperty(const QString &value)
    {
        if (value != m_myProperty) {
            m_myProperty = value;
            emit myPropertyChanged();
        }
    }

signals:
    void myPropertyChanged();

private:
    QString m_myProperty;
};

动态属性和Q_PROPERTY的区别

Q_PROPERTY`和动态属性(Dynamic Properties)是Qt中用于处理对象属性的两种不同机制,它们各有特点和适用场景。以下是它们之间的主要区别:

  1. 定义方式:
  • Q_PROPERTY: 属性是在类的头文件中通过宏定义声明的,需要编译时确定,并且需要相应的getter和setter函数。
  • 动态属性: 属性是在运行时通过QObject::setProperty()QObject::property()方法动态添加和查询的,不需要在类定义中预先声明。
  1. 类型安全:
  • Q_PROPERTY: 提供类型安全,属性的类型在编译时就已经确定,并且可以通过Qt的类型系统进行类型检查。
  • 动态属性: 使用QVariant作为属性值的容器,类型检查是在运行时进行的。
  1. 元数据:
  • Q_PROPERTY: 可以利用元数据提供额外的信息,如属性的描述、默认值、设计able属性等。
  • 动态属性: 通常不包含元数据信息,但可以通过其他方式进行管理。
  1. 信号和槽:
  • Q_PROPERTY: 可以很容易地发出属性改变的信号,并且可以连接到槽函数,实现属性变化的自动通知。
  • 动态属性: 属性变化通常不会自动发出信号,需要手动管理通知机制。
  1. 设计和使用场景:
  • Q_PROPERTY: 适用于需要明确定义属性,并且需要利用Qt属性系统提供的功能,如属性绑定、序列化等的场景。
  • 动态属性: 适用于需要在运行时动态添加或删除属性,或者属性数量和类型在编译时不确定的场景。
  1. 性能:
  • Q_PROPERTY: 由于属性系统高度优化,通常具有较好的性能。
  • 动态属性: 性能可能会略低于Q_PROPERTY,因为它需要在运行时处理属性的存储和检索。
  1. 兼容性:
  • Q_PROPERTY: 可以与Qt Designer等工具集成,支持属性编辑和界面布局。
  • 动态属性: 不直接支持Qt Designer等工具的集成。

8.生命周期Q_PROPERTY的生命周期与类的生命周期相同,通常用于静态属性;动态属性的生命周期是在它被设定到获取删除的过程中,使用者可以在需要时添加或删除。

总结来说,Q_PROPERTY宏提供了一种声明式的方式来定义属性,它具有类型安全、元数据支持、易于集成信号和槽等优点,适用于属性明确且需要利用Qt属性系统的场景。而动态属性则提供了一种灵活的方式来在运行时管理属性,适用于属性数量和类型不确定或需要动态变化的场景.

总结

本文从0开始新建C++和Qt项目,以此展开Qt是如何在C++基础上扩展的。

Qt项目较C++项目的编译流程中添加了moc、uic、qrc编译以支持Qt扩展。

最后简单介绍了Qt的动态属性和Q_PROPERTY两个在C++基础上扩展的核心特性。

像其他的GUI、信号和槽、模型/视图、插件、绘图、动画等核心特性,实际应用较多,这里不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值