【QT】初识qt

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣

在这里插入图片描述


👉🏻项目结构

在Qt框架中,项目结构通常包括几个不同的部分,这些部分帮助组织和管理代码。其中,headerssources、和forms是三个常见的文件夹,它们各自扮演着不同的角色。

  1. Headers(头文件)

Headers 文件夹包含项目的所有头文件(.h 或 .hpp 文件)。头文件主要用于声明类、函数、宏定义等,而不包含具体的实现代码。在Qt项目中,这些头文件通常包含Qt模块的引用、类的声明、以及可能的槽(slots)和信号(signals)的声明(对于使用Qt信号和槽机制的类)。

例如,如果你有一个名为 MainWindow 的类,你可能会有一个名为 mainwindow.h 的头文件,它可能看起来像这样:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#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 slots:
    void on_actionQuit_triggered();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
  1. Sources(源文件)

Sources 文件夹包含项目的所有源文件(.cpp 文件)。源文件包含头文件中声明的类、函数等的具体实现。在Qt项目中,源文件是实现类成员函数、槽(slots)和自定义逻辑的地方。

继续上面的例子,mainwindow.cpp 可能是 mainwindow.h 对应的源文件,它包含 MainWindow 类的实现:

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionQuit_triggered()
{
    qApp->quit();
}
  1. Forms(表单)

Forms 文件夹(虽然在一些Qt项目结构中不总是直接存在,但概念上是类似的)包含由Qt Designer创建的UI表单文件(.ui 文件)。Qt Designer是一个可视化的工具,允许开发者通过拖放控件来创建图形用户界面(GUI)。这些.ui文件在编译时会被uic(UI Compiler)工具转换成对应的C++代码,这些代码通常在源文件中通过包含生成的ui_xxx.h头文件来使用。

在上面的例子中,ui_mainwindow.h 是由Qt Designer的.ui文件(假设名为 mainwindow.ui)通过uic工具生成的,它包含了界面元素的定义和布局。这个文件是自动生成的,通常不需要手动编辑。

综上所述,headerssources、和forms(或.ui文件)在Qt项目中分别扮演着声明接口、实现逻辑、和设计界面的角色。

Q_OBJECT

在Qt框架中,Q_OBJECT宏是元对象系统(Meta-Object System)的核心部分,它为支持信号与槽(Signals & Slots)、属性(Properties)、以及对象间运行时类型信息(Run-time Type Information, RTTI)等功能的类提供了一种机制。因此,当你想要在一个Qt类中使用这些特性时,你需要在类声明的开始处包含Q_OBJECT宏。

具体来说,Q_OBJECT宏做了以下几件事情:

  1. 启用信号与槽机制:Qt的信号与槽机制是对象间通信的一种方式,它允许对象在特定事件发生时发出信号,而其他对象可以通过槽来响应这些信号。Q_OBJECT宏使得类能够注册其信号和槽,从而允许Qt的元对象系统在运行时连接和管理它们。

  2. 支持运行时类型信息和动态属性系统:通过Q_OBJECT宏,Qt能够获取对象的类型信息(如类名),这在进行类型检查或类型转换时非常有用。此外,它还允许类拥有动态属性,这些属性可以在运行时被添加、修改或查询,为类的功能扩展提供了极大的灵活性。

  3. 事件处理:虽然Q_OBJECT宏本身不直接处理事件,但它使得类能够继承自QObject(或QObject的子类),从而能够利用Qt的事件系统。这对于创建能够响应各种用户输入和系统事件的图形界面应用程序至关重要。

  4. 对象树和父子关系:Qt使用对象树来管理内存。当一个QObject的子对象被销毁时,它的所有子对象也会被自动销毁,这有助于防止内存泄漏。Q_OBJECT宏使得类能够参与这种父子关系的管理。

  5. 国际化(i18n)支持:虽然国际化不是Q_OBJECT宏的直接作用,但Qt的国际化系统(如使用tr()函数进行字符串翻译)依赖于元对象系统来识别需要翻译的字符串。因此,使用Q_OBJECT宏的类可以更方便地利用Qt的国际化功能。

综上所述,Q_OBJECT宏是Qt元对象系统的基础,它使得Qt类能够利用信号与槽、运行时类型信息、动态属性、事件处理、对象树和国际化等强大功能。因此,在开发Qt应用程序时,如果你打算使用这些功能,就必须在类声明中包含Q_OBJECT宏。

👉🏻使用QPushButton在窗口显示hello qt

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setFixedSize(1000,900);//设置窗口大小

    QPushButton* btn = new QPushButton();//创建按钮对象
    btn->setText("hello qt");//设置文本
    btn->setParent(this);//将按钮置于窗口上
    btn->move(450,300);

    //设置字体属性
    QFont front("宋体",24);
    btn->setFont(front);
    btn->setStyleSheet("color:red");
}

Widget::~Widget()
{
    delete ui;
}

在这里插入图片描述

btn->setParent(this);这行代码在这个上下文中是多余的,因为move已经隐含了父子关系

👉🏻对象树

Qt中的对象树是Qt框架中一个非常重要的概念,它不仅是Qt管理内存、处理事件和组织用户界面元素的基础,还极大地简化了资源的生命周期管理和事件的传播。以下是对Qt对象树的详细解析:

一、对象树的基本概念

在Qt中,对象树是一种特殊的对象关系结构,其中每个对象(节点)可以有零个或多个子对象(子节点),形成了一个层次化的结构。这种结构通过QObject类的父子关系实现,每个QObject对象在创建时可以指定一个父对象,当父对象被销毁时,其下的所有子对象也会被自动销毁,从而实现了内存的自动回收。

二、对象树的构造与析构

  1. 构造过程

    • 当创建一个QObject对象时,可以通过构造函数中的Parent参数指定其父对象。
    • 如果指定了父对象,新创建的QObject对象会自动添加到父对象的children()列表中。
    • 如果没有指定父对象(即Parent参数为nullptr),则新创建的QObject对象成为一个顶级对象,不会被任何QObject对象自动管理其生命周期。
  2. 析构过程

    • 当一个QObject对象(父对象)被销毁时,Qt会自动销毁其children()列表中的所有子对象。
    • 析构的顺序与构造的顺序相反,即先析构子对象,再析构父对象。
    • 这种机制确保了即使在复杂的对象关系中,也不会出现内存泄漏的问题。

三、对象树的作用

  1. 内存管理自动化

    • 对象树提供了自动的内存回收机制,避免了手动管理内存时可能出现的错误和复杂性。
    • 当不再需要某个对象时,只需确保其父对象被销毁即可,无需逐一删除所有子对象。
  2. 事件传播

    • Qt的事件系统能够沿着对象树传播事件,如鼠标点击或键盘输入等。
    • 子对象可以重写事件处理函数来响应特定事件,而无需在每个对象上单独设置事件监听器。
  3. 布局和渲染

    • 在用户界面设计中,对象树帮助保持组件的布局和渲染顺序。
    • 通过对象树,可以更容易地管理组件之间的相对位置和大小关系。

四、注意事项

  1. 避免循环引用

    • 在构建对象树时,要确保没有形成环状引用,否则会导致部分对象无法正确销毁。
  2. 手动管理未加入对象树的对象

    • 并非所有对象都需要或应该加入对象树。对于这些对象,务必在不再需要时手动调用delete来释放内存。
  3. 堆上创建对象

    • 尽量在堆上创建QObject对象及其子类的对象,以避免在栈上创建时可能出现的析构顺序问题。
  4. 对象所有权转移

    • 在某些情况下,可能需要改变对象的父对象以转移内存管理的责任。这可以通过调用setParent()函数来实现。

五、示例代码

以下是一个简单的示例代码,展示了如何在Qt中构建对象树:

#include <QApplication>
#include <QWidget>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个QWidget对象作为主窗口
    QWidget *mainWindow = new QWidget();

    // 创建一个QPushButton对象,并指定mainWindow为其父对象
    QPushButton *button = new QPushButton("Click me!", mainWindow);

    // 显示主窗口及其所有子对象(包括按钮)
    mainWindow->show();

    return app.exec();
}

在这个示例中,QPushButton对象被添加到了QWidget对象的children()列表中,从而形成了对象树。当mainWindow被销毁时(例如应用程序退出时),Qt会自动销毁button对象,避免了内存泄漏。

👉🏻qDebug

在Qt中,qDebug() 是一个非常有用的宏,用于在调试期间输出信息到标准输出(通常是控制台或调试器输出窗口)。这个宏提供了类似于标准C++流(如 std::cout)的接口,但专为Qt应用程序设计,能够更好地与Qt的日志系统和调试工具集成。

qDebug() 宏本身不需要你显式地包含某个特定的“QDebug”头文件来使用它。相反,它通常是通过包含Qt的核心模块头文件(如 <QCoreApplication><QObject> 或其他Qt模块头文件)而间接可用的。这些头文件内部会包含必要的定义,使得 qDebug() 宏可以在你的代码中使用。

然而,如果你想要为你的自定义类型提供对 qDebug() 的支持,即让 qDebug() 能够输出你的自定义类型的信息,你需要在你的类型中重载 QDebug<< 操作符。为了做到这一点,你通常需要包含 <QDebug> 头文件(尽管这不是严格要求的,因为Qt的元对象系统可能会通过其他方式提供这种支持,但包含 <QDebug> 是一种更明确和可移植的做法)。

下面是一个为自定义类型重载 QDebug<< 操作符的示例:

#include <QDebug> // 包含QDebug支持

class MyCustomClass {
public:
    MyCustomClass(int value) : m_value(value) {}

    // 自定义的qDebug()输出
    friend QDebug operator<<(QDebug debug, const MyCustomClass &myClass) {
        QDebugStateSaver saver(debug); // 保存当前QDebug的状态
        debug.nospace() << "MyCustomClass(" << myClass.m_value << ")";
        return debug;
    }

private:
    int m_value;
};

// 使用示例
int main() {
    MyCustomClass myObject(42);
    qDebug() << "This is a custom object:" << myObject;
    return 0;
}

在这个示例中,我们包含了 <QDebug> 头文件以支持为 MyCustomClass 重载 QDebug<< 操作符。然后,我们在 main() 函数中使用 qDebug() 来输出一个 MyCustomClass 类型的对象,并看到自定义的输出格式。

请注意,虽然包含 <QDebug> 头文件不是使用 qDebug() 的必要条件,但它是为你的自定义类型提供对 qDebug() 支持的推荐做法。


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值