Qt学习笔记01:Qt核心基础

一、Qt核心基础认知

Qt是一款跨平台的C++应用程序开发框架,由Qt Company(原Nokia)维护,凭借其简洁的API、强大的跨平台能力和丰富的功能模块,成为桌面(Windows/Linux/macOS)、嵌入式(ARM/Linux)、移动端(Android/iOS)等领域开发的主流选择。想要学好Qt,首先要掌握其核心基础认知,包括跨平台原理、版本与模块选择两部分核心内容。

1.1 跨平台原理

Qt的跨平台特性是其核心优势之一,核心实现逻辑分为封装系统API自绘组件两部分,具体实现细节如下:

  • 封装系统API:不同操作系统的底层核心接口(如窗口创建、文件操作、网络通信)存在本质差异:
    • Windows系统:窗口创建依赖CreateWindowEx API,文件操作依赖CreateFile/ReadFile等API;
    • Linux系统:窗口创建依赖X11/Wayland协议的底层接口,文件操作依赖open/read等POSIX标准API;
    • macOS系统:窗口创建依赖Cocoa框架的NSWindow,文件操作依赖fopen/fread等BSD风格API。
      Qt在这些原生API之上封装了一层统一的抽象接口(如QWidget封装窗口创建、QFile封装文件操作),开发者调用Qt的API时,Qt的底层适配层会根据当前运行的操作系统,自动将Qt API映射到对应的系统原生API,无需开发者针对不同系统编写差异化代码。
  • 自绘组件:传统原生控件(如Windows的Button控件、Linux的GTK Button控件)的外观渲染、事件响应逻辑差异极大,Qt提供了基于QWidget的自绘组件体系:
    • 组件的渲染逻辑(如按钮的绘制、文字的显示)由Qt的QPainter模块统一实现,不依赖系统原生控件的渲染逻辑;
    • 组件的事件响应(如点击、拖拽)由Qt的事件循环系统统一处理,保证同一套代码在不同系统下的UI外观、交互行为100%一致。

1.2 版本与模块选择

1.2.1 版本选择

目前Qt的主流版本为Qt5(最新LTS版本5.15)和Qt6(最新LTS版本6.6),两者核心差异如下(补充技术细节):

  • Qt5:
    • 底层兼容C++11/14标准,编译器支持范围广(如MSVC 2013、GCC 4.8);
    • 生态成熟,第三方库(如OpenCV、Boost)的Qt适配版本全覆盖;
    • 模块耦合度略高(如Qt Gui模块包含部分Widgets功能);
    • 是目前企业级项目(尤其是嵌入式、传统桌面应用)的主流选择,覆盖90%以上的开发场景。
  • Qt6:
    • 基于C++17重构,底层移除大量老旧代码,内存占用降低约15%,运行效率提升约20%;
    • 模块化更精细(如将Qt Core拆分为Qt Core、Qt Core5Compat);
    • 新增Qt Quick 3D(三维界面开发)、Qt WebAssembly(Web端适配)、Qt StateMachine(状态机框架)等新特性;
    • 部分老旧第三方库(如Qt5的QAxContainer)兼容度不足,适合新项目、对性能/新特性有需求的场景。
1.2.2 模块选择

Qt的功能以“模块”为单位划分,分为核心模块(必选/高频使用)和扩展模块(按需引入),各模块的核心类与功能补充如下:

  • 核心模块:
    • Qt Core:Qt的核心基础模块,提供内存管理(父子对象机制)、容器类(QList/QMap)、事件处理(QEvent)、元对象系统(Q_OBJECT宏/反射)、基础数据类型(QString/QVariant)等底层能力,所有Qt项目默认依赖;核心类包括QObject(所有Qt对象的基类)、QString(字符串)、QVariant(万能类型)、QTimer(定时器)。
    • Qt Gui:提供图形渲染(QPainter)、字体(QFont)、图像(QImage/QPixmap)、颜色(QColor)、输入设备(QMouseEvent/QKeyEvent)等基础图形界面能力,是Qt Widgets/Qt Quick的依赖模块;核心类包括QPainter(绘图)、QImage(图像处理)、QGuiApplication(图形界面应用入口)。
    • Qt Widgets:提供传统桌面端UI组件(按钮、输入框、布局等),是桌面应用开发的核心模块;核心类包括QWidget(所有控件的基类)、QPushButton(按钮)、QLineEdit(输入框)、QMainWindow(主窗口)。
  • 扩展模块:
    • QtNetwork:网络通信(TCP/UDP/WebSocket),核心类QTcpSocket/QTcpServer/QUdpSocket/QWebSocket
    • Qt Sql:数据库操作,核心类QSqlDatabase(数据库连接)/QSqlQuery(SQL执行);
    • Qt Concurrent:并行计算,核心接口QtConcurrent::run(多线程任务);
    • Qt Multimedia:音视频处理,核心类QMediaPlayer(音视频播放)/QCamera(相机)。

二、Qt工程文件核心配置

Qt工程的核心配置文件是.pro文件(Qt Creator默认生成),采用基于Makefile的简化语法,掌握其配置规则是搭建Qt工程的基础,包括基础配置、子目录工程、条件编译三部分,以下补充更具体的配置规则和细节。

2.1 .pro文件基础配置

.pro文件的核心配置项包括QT模块、TARGET、SOURCES/HEADERS/FORMS,以下是优化后的基础Qt Widgets工程示例(补充配置项说明和扩展用法):

# 在项目文件中, 注释需要使用 井号(#)
# 1. QT模块配置:声明工程依赖的Qt模块,+=表示追加,-=表示移除,=表示覆盖
QT       += core gui  # 基础依赖:核心模块+图形模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets  # Qt5+需显式添加widgets模块(Qt4中包含在gui中)
# 扩展用法:移除不需要的模块(如移除Qt Network)
# QT -= network

# 2. 编译特性配置:CONFIG用于设置编译模式、C++标准、工程特性等
CONFIG += c++17	# 指定使用C++17标准(Qt5.14+支持,Qt6默认C++17)
CONFIG += debug  # 编译为调试版本(release为发布版本,debug_and_release为同时编译)
CONFIG += warn_on  # 开启所有编译警告(warn_off关闭)

# 3. 宏定义配置:DEFINES用于定义预编译宏,等价于C++中的#define
DEFINES += QT_DEPRECATED_WARNINGS  # 调用废弃函数时触发编译警告
DEFINES += APP_VERSION="\"1.0.0\""  # 定义字符串宏(需嵌套引号)
DEFINES += MAX_COUNT=100  # 定义数值宏

# 4. 工程输出配置
TARGET = QtBasicDemo  # 工程编译后的可执行文件名称(Windows:.exe,Linux:无后缀,macOS:.app)
TEMPLATE = app  # 工程类型:app=可执行程序,lib=静态/动态库,subdirs=子目录工程
DESTDIR = ./bin  # 可执行文件输出目录(默认在构建目录)
OBJECTS_DIR = ./obj  # 中间目标文件(.o/.obj)输出目录
MOC_DIR = ./moc  # moc工具生成的代码输出目录(处理Q_OBJECT宏)
UIC_DIR = ./ui  # uic工具生成的UI代码输出目录(处理.ui文件)
RCC_DIR = ./rcc  # rcc工具生成的资源代码输出目录(处理.qrc文件)

# 5. 文件列表配置:SOURCES(源文件)/HEADERS(头文件)/FORMS(UI文件)/RESOURCES(资源文件)
SOURCES += \
        main.cpp \
        mainwindow.cpp
        
HEADERS += \
        mainwindow.h
        
FORMS += \
        mainwindow.ui

# 6. 资源文件配置(可选):.qrc文件用于管理图片、字体等资源
# RESOURCES += res.qrc

2.2 子目录工程配置

当项目规模较大时(如拆分UI模块、网络模块、业务模块),需要使用子目录工程,核心是通过SUBDIRS配置子工程路径,补充子工程的依赖规则和进阶用法:

示例:主工程QtSubDirDemo.pro

# 声明工程类型为子目录工程(必须放在首位)
TEMPLATE = subdirs

# 子工程列表:按顺序编译(可通过.depends指定依赖)
SUBDIRS += ui_module \
           network_module \
           business_module

# 指定子工程依赖关系:先编译依赖的子工程,再编译当前子工程
network_module.depends = ui_module  # network_module依赖ui_module
business_module.depends = ui_module network_module  # business_module依赖前两个模块

# 为每个子工程指定.pro文件路径(若子工程目录名与.pro文件名一致,可省略.file配置)
ui_module.file = ui_module/ui_module.pro
network_module.file = network_module/network_module.pro
business_module.file = business_module/business_module.pro

# 扩展:设置子工程的构建目录(默认在主工程构建目录下)
ui_module.builddir = ./build/ui_module
network_module.builddir = ./build/network_module

子工程ui_module.pro示例(补充库类型配置):

QT += widgets
TEMPLATE = lib  # 子工程可编译为库(静态库/动态库)
CONFIG += staticlib  # 指定为静态库(sharedlib为动态库)
TARGET = ui_module  # 库文件名称(Windows:.lib/.dll,Linux:.a/.so,macOS:.a/.dylib)
DESTDIR = ./lib  # 库文件输出目录

SOURCES += ui_widget.cpp
HEADERS += ui_widget.h

# 扩展:导出库的头文件路径(供其他子工程引用)
INCLUDEPATH += ./ui_module

2.3 条件编译

条件编译允许根据不同场景(如操作系统、Qt版本、自定义宏)编译不同代码,核心是DEFINES(定义宏)、CONFIG(配置项),以及contains/equals/greaterThan/lessThan等条件判断语法,补充更多实用示例和语法细节:

语法基础
语法 说明 示例
contains(VAR, VALUE) 判断VAR是否包含VALUE contains(DEFINES, ENABLE_LOG)
equals(VAR, VALUE) 判断VAR是否等于VALUE equals(QT_MAJOR_VERSION, 6)
greaterThan(VAR, VALUE) 判断VAR是否大于VALUE greaterThan(QT_VERSION, 5.15)
lessThan(VAR, VALUE) 判断VAR是否小于VALUE lessThan(QT_VERSION, 6.0)
win32/linux/macx 操作系统专属条件(内置) win32 { ... }
示例1:定义自定义宏,控制功能开关
# 定义宏ENABLE_LOG(等价于C++中的#define ENABLE_LOG)
DEFINES += ENABLE_LOG

# 条件编译:如果定义了ENABLE_LOG,引入日志相关文件
contains(DEFINES, ENABLE_LOG) {
    SOURCES += log_helper.cpp
    HEADERS += log_helper.h
    # 追加日志宏定义
    DEFINES += LOG_LEVEL=3  # 3=DEBUG级别
} else {
    DEFINES += LOG_LEVEL=1  # 1=ERROR级别
}
示例2:根据操作系统编译差异化代码
# Windows系统(win32包含32/64位,win64可指定64位)
win32 {
    # 引入Windows特有的库(-l表示链接库,user32是Windows系统库)
    LIBS += -luser32 -lkernel32
    # 定义Windows宏
    DEFINES += OS_WINDOWS
    # 设置Windows专属输出目录
    DESTDIR = ./bin/win32
}

# Linux系统(linux包含x86/ARM等架构)
linux {
    # 引入Linux特有的库(pthread是线程库)
    LIBS += -lpthread -lrt
    DEFINES += OS_LINUX
    DESTDIR = ./bin/linux
}

# macOS系统
macx {
    DEFINES += OS_MAC
    # macOS专属编译选项
    QMAKE_CXXFLAGS += -stdlib=libc++
    DESTDIR = ./bin/macx
}
示例3:根据Qt版本编译差异化代码
# Qt6及以上版本
greaterThan(QT_MAJOR_VERSION, 5) {
    DEFINES += QT6_VERSION
    # Qt6移除的模块,替换为Qt Core5Compat
    QT += core5compat
} else {
    # Qt5版本
    DEFINES += QT5_VERSION
    # Qt5专属模块
    QT += multimediawidgets
}

三、Qt窗口基类与内存管理

Qt的窗口开发基于三大核心基类(QMainWindow/QWidget/QDialog),且其独特的父子对象机制(基于QObject)简化了内存管理,同时窗口坐标系统是UI布局和交互的基础,以下补充各基类的核心函数原型和内存管理的细节。

3.1 三大窗口基类

3.1.1 QMainWindow

QMainWindow是带完整桌面应用框架的窗口类,内置菜单栏(QMenuBar)、工具栏(QToolBar)、状态栏(QStatusBar)、中心窗口(centralWidget),适合作为应用的主窗口。

核心函数原型
// 构造函数
QMainWindow::QMainWindow(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

// 菜单栏相关
// 获取/设置菜单栏(QMainWindow会接管菜单栏的内存)
QMenuBar *QMainWindow::menuBar() const;
void QMainWindow::setMenuBar(QMenuBar *menuBar);

// 工具栏相关
QToolBar *QMainWindow::addToolBar(const QString &title);
void QMainWindow::addToolBar(Qt::ToolBarArea area, QToolBar *toolbar);
void QMainWindow::removeToolBar(QToolBar *toolbar);

// 状态栏相关
QStatusBar *QMainWindow::statusBar() const;
void QMainWindow::setStatusBar(QStatusBar *statusBar);

// 中心窗口相关(QMainWindow必须设置中心窗口,否则空白区域无法响应事件)
void QMainWindow::setCentralWidget(QWidget *widget);
QWidget *QMainWindow::centralWidget() const;

// 窗口属性
void QMainWindow::setWindowTitle(const QString &title);
QString QMainWindow::windowTitle() const;
void QMainWindow::resize(int w, int h);
void QMainWindow::resize(const QSize &size);
void QMainWindow::show(); // 显示窗口(非模态)
代码示例:创建带菜单栏/工具栏/状态栏的QMainWindow
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>

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

    // 创建主窗口(构造函数:父对象为nullptr,窗口标志为默认)
    QMainWindow w(nullptr, Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
    w.setWindowTitle("QMainWindow Demo");
    w.resize(800, 600);

    // 1. 创建菜单栏
    QMenuBar *menuBar = w.menuBar();
    QMenu *fileMenu = menuBar->addMenu("文件(&F)"); // &F表示快捷键Alt+F
    QAction *newAction = fileMenu->addAction(QIcon(":/icons/new.png"), "新建(&N)"); // 带图标
    QAction *openAction = fileMenu->addAction("打开(&O)");
    fileMenu->addSeparator(); // 添加分隔线
    QAction *exitAction = fileMenu->addAction("退出(&E)");

    // 绑定退出信号与槽
    QObject::connect(exitAction, &QAction::triggered, &a, &QApplication::quit);

    // 2. 创建工具栏
    QToolBar *toolBar = w.addToolBar("主工具栏");
    toolBar->addAction(newAction); // 复用菜单栏的Action
    toolBar->addAction(openAction);

    // 3. 创建状态栏
    QStatusBar *statusBar = w.statusBar();
    statusBar->addWidget(new QLabel("就绪")); // 左侧提示
    statusBar->addPermanentWidget(new QLabel("v1.0.0")); // 右侧永久显示

    // 4. 设置中心窗口
    QWidget *centralWidget = new QWidget(&w);
    w.setCentralWidget(centralWidget);

    w.show();
    return a.exec();
}

示例代码运行效果展示:
在这里插入图片描述

3.1.2 QWidget

QWidget是通用的空白窗口类,是所有UI组件(包括QMainWindowQDialogQPushButton)的基类,支持自定义绘制、事件响应,适合作为自定义控件或简单窗口。

核心函数原型
// 构造函数
QWidget::QWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

// 父对象管理(继承自QObject,重写以适配窗口层级)
void QWidget::setParent(QWidget *parent);
void QWidget::setParent(QWidget *parent, Qt::WindowFlags f);
QWidget *QWidget::parentWidget() const; // 获取父窗口,无则返回nullptr

// 窗口位置与尺寸
void QWidget::move(int x, int y); // 设置客户区左上角坐标(父窗口坐标系)
void QWidget::move(const QPoint &pos);
QPoint QWidget::pos() const; // 获取窗口左上角坐标(父窗口坐标系)

void QWidget::resize(int w, int h);
void QWidget::resize(const QSize &size);
QSize QWidget::size() const;

void QWidget::setGeometry(int x, int y, int w, int h); // 一次性设置位置+尺寸
QRect QWidget::geometry() const;

// 窗口显示与隐藏
void QWidget::show(); // 显示窗口(非模态)
void QWidget::hide(); // 隐藏窗口
bool QWidget::isVisible() const; // 判断是否可见

// 事件重写(自定义控件核心)
protected:
void QWidget::paintEvent(QPaintEvent *event); // 绘制事件(自定义绘制)
void QWidget::mousePressEvent(QMouseEvent *event); // 鼠标按下事件
void QWidget::keyPressEvent(QKeyEvent *event); // 键盘按下事件
void QWidget::resizeEvent(QResizeEvent *event); // 窗口大小变化事件

代码示例:创建带按钮的自定义QWidget
#include <QApplication>
#include <QWidget>
#include <QPushButton>

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

    // 创建空白窗口
    QWidget w;
    w.setWindowTitle("QWidget Demo");
    w.resize(400, 300);

    // 创建按钮(父对象为w,按钮会显示在w的窗口内)
    QPushButton *btn = new QPushButton("点击我", &w);
    // 设置按钮位置(绝对定位)
    btn->move(150, 120);

    w.show();
    return a.exec();
}


示例代码运行效果展示:
在这里插入图片描述

3.1.3 QDialog

QDialog是对话框窗口类,用于临时交互(如提示、输入、选择),支持模态/非模态显示,内置对话框按钮盒(QDialogButtonBox),适合作为功能弹窗。

核心函数原型
// 构造函数
QDialog::QDialog(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

// 显示模式(核心差异)
int QDialog::exec(); // 模态显示:阻塞主窗口,返回对话框结果(QDialog::Accepted/Rejected)
void QDialog::show(); // 非模态显示:不阻塞主窗口,独立显示
void QDialog::open(); // 半模态显示:阻塞主窗口,但允许事件循环处理(Qt5+)

// 对话框结果
void QDialog::setResult(int result);
int QDialog::result() const;
void QDialog::accept(); // 确认:设置result为Accepted,关闭对话框
void QDialog::reject(); // 取消:设置result为Rejected,关闭对话框

// 按钮盒(简化对话框按钮布局)
void QDialog::setDialogButtonBox(QDialogButtonBox *buttonBox);
QDialogButtonBox *QDialog::dialogButtonBox() const;

代码示例:创建带按钮盒的模态对话框
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QDialog>
#include <QLabel>
#include <QDialogButtonBox>
#include <QVBoxLayout>

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

    QWidget w;
    w.setWindowTitle("主窗口");
    w.resize(400, 300);

    QPushButton *btn = new QPushButton("打开对话框", &w);
    btn->move(150, 120);

    // 绑定按钮点击信号
    QObject::connect(btn, &QPushButton::clicked, [&]() {
        // 创建对话框(父对象为w,继承父窗口的样式)
        QDialog dlg(&w, Qt::Dialog | Qt::WindowCloseButtonHint);
        dlg.setWindowTitle("提示对话框");
        dlg.resize(300, 150);

        // 创建布局(避免绝对定位)
        QVBoxLayout *layout = new QVBoxLayout(&dlg);
        QLabel *label = new QLabel("是否确认执行该操作?", &dlg);
        label->setAlignment(Qt::AlignCenter);

        // 创建按钮盒(内置确认/取消按钮)
        QDialogButtonBox *buttonBox = new QDialogButtonBox(
            QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg);
        // 绑定按钮信号
        connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
        connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);

        // 添加控件到布局
        layout->addWidget(label);
        layout->addWidget(buttonBox);

        // 模态显示:阻塞主窗口,直到对话框关闭
        int result = dlg.exec();
        if (result == QDialog::Accepted) {
            btn->setText("已确认");
        } else {
            btn->setText("已取消");
        }
    });

    w.show();
    return a.exec();
}

示例代码运行效果展示:

在这里插入图片描述

三大基类核心区别总结
类名 核心特性 适用场景 关键函数
QMainWindow 内置菜单栏/工具栏/状态栏,必须设置中心窗口 应用主窗口(如编辑器、浏览器主界面) menuBar()/setCentralWidget()
QWidget 通用空白窗口,所有控件的基类,支持自定义绘制 自定义控件、简单窗口、容器控件 paintEvent()/setParent()
QDialog 支持模态/非模态显示,内置按钮盒 临时交互弹窗(提示、输入、确认) exec()/accept()/reject()

3.2 父子对象机制(内存管理核心)

Qt的父子对象机制是基于QObject实现的内存管理方案,无需手动管理大部分对象的内存,核心规则补充具体实现细节和函数原型:

核心规则
  1. 当一个QObject子类对象(如QWidgetQPushButton)设置了父对象:
    • 子对象会被加入父对象的“子对象列表”(QObject::children());
    • 父对象销毁时(析构函数),会遍历子对象列表,逐个调用delete销毁所有子对象;
    • 子对象的生命周期由父对象管理,无需手动delete
  2. 手动删除子对象时:
    • 子对象会自动从父对象的子对象列表中移除(避免父对象重复销毁);
    • 触发QObject::destroyed()信号,可用于监听子对象销毁。
  3. 栈对象作为子对象:
    • 栈对象销毁时(如函数结束),会自动调用setParent(nullptr)脱离父对象列表;
    • 父对象销毁时不会重复销毁栈对象,避免双重释放。
核心函数原型
// 父对象设置
void QObject::setParent(QObject *parent);
QObject *QObject::parent() const; // 获取父对象(返回QObject*,需强转为QWidget*)

// 子对象管理
QList<QObject *> QObject::children() const; // 获取所有直接子对象
QObject *QObject::findChild(const QString &name, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const; // 查找子对象
QList<QObject *> QObject::findChildren(const QString &name, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const;

// 销毁子对象
void QObject::deleteLater(); // 延迟销毁:将销毁操作加入事件循环,避免当前事件处理中销毁对象
bool QObject::destroyed(QObject *obj); // 信号:对象销毁时触发

代码示例:父子对象机制演示
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <qDebug>

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

    // 创建父对象(堆对象)
    QWidget *w = new QWidget;
    w->setWindowTitle("父子对象机制");
    w->resize(400, 300);
    w->setObjectName("MainWindow"); // 设置对象名,用于findChild

    // 创建子对象1:构造函数指定父对象
    QPushButton *btn1 = new QPushButton("按钮1", w);
    btn1->setObjectName("Button1");
    btn1->move(100, 100);

    // 创建子对象2:手动设置父对象
    QPushButton *btn2 = new QPushButton("按钮2");
    btn2->setParent(w); // 调用QObject::setParent
    btn2->move(200, 100);

    // 演示:获取父对象的子对象列表
    qDebug() << "父对象的子对象数量:" << w->children().size(); // 2
    // 查找指定名称的子对象
    QPushButton *findBtn = w->findChild<QPushButton*>("Button1");
    if (findBtn) {
        qDebug() << "找到子对象:" << findBtn->text(); // "按钮1"
    }

    w->show();

    // 运行程序后关闭窗口,w被销毁时自动销毁btn1和btn2
    int ret = a.exec();
    delete w; // 销毁父对象,触发子对象销毁
    qDebug() << "父对象已销毁,子对象自动销毁";
    return ret;
}

示例代码运行效果展示:QObject_demo

在这里插入图片描述

常见坑点
  1. 避免循环父对象:A设置B为父对象,B又设置A为父对象,会导致析构时死循环;
  2. deleteLater()的使用场景:在信号槽中销毁当前对象(如connect(btn, &QPushButton::clicked, this, &MyWidget::deleteLater)),避免直接delete this导致崩溃;
  3. 动态创建的子对象:若未设置父对象,必须手动delete,否则内存泄漏。

3.3 窗口坐标系统

Qt的坐标系统分为客户区坐标全局坐标,补充坐标转换的函数原型和更具体的使用场景:

3.3.1 坐标类型
  • 客户区坐标:
    • 原点:窗口的左上角(不含标题栏、边框);
    • 坐标系:x轴向右,y轴向下;
    • 适用场景:控件在窗口内的定位、鼠标在窗口内的位置。
  • 全局坐标:
    • 原点:屏幕的左上角(多屏幕时,主屏幕为原点);
    • 坐标系:x轴向右,y轴向下;
    • 适用场景:多窗口交互、屏幕截图、鼠标全局位置。
3.3.2 坐标转换函数原型
// 客户区坐标 → 全局坐标
QPoint QWidget::mapToGlobal(const QPoint &pos) const;

// 全局坐标 → 客户区坐标
QPoint QWidget::mapFromGlobal(const QPoint &pos) const;

// 客户区坐标 → 父窗口坐标(父窗口的客户区)
QPoint QWidget::mapToParent(const QPoint &pos) const;

// 父窗口坐标 → 客户区坐标
QPoint QWidget::mapFromParent(const QPoint &pos) const;

// 客户区坐标 → 任意窗口坐标
QPoint QWidget::mapTo(const QWidget *parent, const QPoint &pos) const;

// 任意窗口坐标 → 客户区坐标
QPoint QWidget::mapFrom(const QWidget *parent, const QPoint &pos) const;

// 获取鼠标位置
QPoint QWidget::mapFromGlobal(const QPoint &globalPos) const; // 全局→当前窗口
QPoint QCursor::pos(); // 获取鼠标全局坐标(静态函数)
void QCursor::setPos(const QPoint &pos); // 设置鼠标全局坐标(静态函数)

代码示例:坐标转换与鼠标位置监听
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QMouseEvent>
#include <qDebug>

class MyWidget : public QWidget {
    Q_OBJECT
public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("坐标转换演示");
        resize(400, 300);
        btn = new QPushButton("点击查看坐标", this);
        btn->move(150, 120);

        // 绑定按钮点击:获取按钮的全局坐标
        connect(btn, &QPushButton::clicked, this, [=]() {
            QPoint btnLocalPos = btn->pos(); // 按钮在当前窗口的客户区坐标
            QPoint btnGlobalPos = btn->mapToGlobal(btnLocalPos); // 转换为全局坐标
            qDebug() << "按钮客户区坐标:" << btnLocalPos;
            qDebug() << "按钮全局坐标:" << btnGlobalPos;
        });
    }

protected:
    // 重写鼠标点击事件:获取鼠标坐标
    void mousePressEvent(QMouseEvent *event) override {
        // 1. 鼠标在当前窗口的客户区坐标
        QPoint localPos = event->pos();
        // 2. 转换为全局坐标
        QPoint globalPos = mapToGlobal(localPos);
        // 3. 全局坐标转回客户区坐标
        QPoint localPos2 = mapFromGlobal(globalPos);

        qDebug() << "鼠标客户区坐标:" << localPos;
        qDebug() << "鼠标全局坐标:" << globalPos;
        qDebug() << "转回客户区坐标:" << localPos2;

        // 4. 获取鼠标全局坐标(静态函数)
        QPoint cursorGlobalPos = QCursor::pos();
        qDebug() << "鼠标全局坐标(QCursor):" << cursorGlobalPos;
    }

private:
    QPushButton *btn;
};

#include "main.moc" // moc工具生成的代码(处理Q_OBJECT宏)
int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MyWidget w;
    w.show();
    return a.exec();
}

示例代码运行效果展示:CoordinateConversion_MousePosListening

在这里插入图片描述

四、Qt核心数据类型

Qt在C++原生类型基础上封装了核心数据类型,解决了原生类型的跨平台、Unicode支持、易用性问题,其中QStringQVariant是最常用的两个,补充核心函数原型和更具体的使用场景。

4.1 QString

QString是Qt封装的Unicode字符串类型(基于UTF-16编码),解决了C++原生std::string不支持Unicode、接口繁琐的问题,补充核心函数原型和进阶用法。

核心函数原型
// 构造函数
QString::QString(); // 空字符串
QString::QString(const char *str); // 从C字符串(UTF-8)构造
QString::QString(const QString &other); // 拷贝构造
QString::QString(int size, QChar ch); // 构造指定长度、字符的字符串

// 字符串拼接
QString &QString::append(const QString &str); // 尾部追加
QString &QString::prepend(const QString &str); // 头部追加
QString QString::arg(const QString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const; // 格式化替换
QString operator+(const QString &a, const QString &b); // 重载+运算符

// 类型转换
int QString::toInt(bool *ok = nullptr, int base = 10) const; // 转int(base为进制,默认10)
double QString::toDouble(bool *ok = nullptr) const; // 转double
float QString::toFloat(bool *ok = nullptr) const; // 转float
QByteArray QString::toUtf8() const; // 转UTF-8的QByteArray(C字符串用.data())
static QString QString::number(int n, int base = 10); // 静态函数:数值转字符串
static QString QString::number(double n, char format = 'g', int precision = 6); // 浮点数转字符串
static QString QString::fromUtf8(const char *str, int size = -1); // 从UTF-8 C字符串构造

// 查找/替换
int QString::indexOf(const QString &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; // 查找子串(返回索引,无则-1)
bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; // 是否包含子串
QString &QString::replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive); // 替换子串

// 其他常用函数
int QString::length() const; // 字符串长度(字符数)
bool QString::isEmpty() const; // 是否为空(长度0)
bool QString::isNull() const; // 是否为null(仅默认构造的空字符串为null)
QString QString::trimmed() const; // 去除首尾空白字符
QString QString::simplified() const; // 去除首尾空白,中间多个空白替换为一个

代码示例:QString进阶用法
#include <QApplication>
#include <QString>
#include <qDebug>

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

    // 1. 构造函数
    QString str1; // 空字符串(isNull()=true,isEmpty()=true)
    QString str2 = "Hello Qt"; // 从C字符串构造
    QString str3(5, 'A'); // "AAAAA"
    qDebug() << "str1是否为null:" << str1.isNull() << ",是否为空:" << str1.isEmpty();

    // 2. 拼接(arg格式化推荐)
    QString name = "张三";
    int age = 25;
    double score = 98.5;
    QString info = QString("姓名:%1,年龄:%2,成绩:%3").arg(name).arg(age).arg(score, 0, 'f', 1);
    qDebug() << "格式化信息:" << info; // "姓名:张三,年龄:25,成绩:98.5"

    // 3. 类型转换(带错误处理)
    QString numStr = "12345";
    bool ok;
    int num = numStr.toInt(&ok);
    if (ok) {
        qDebug() << "numStr转int:" << num;
    } else {
        qDebug() << "转换失败";
    }

    // 非法转换(含字母)
    QString badStr = "12a3";
    int badNum = badStr.toInt(&ok);
    qDebug() << "badStr转int是否成功:" << ok << ",值:" << badNum; // ok=false,值=0

    // 4. 查找/替换
    QString str = "Qt is a cross-platform framework, Qt is powerful";
    int firstIndex = str.indexOf("Qt"); // 0
    int secondIndex = str.indexOf("Qt", firstIndex + 1); // 32
    qDebug() << "Qt首次出现位置:" << firstIndex << ",第二次:" << secondIndex;

    // 忽略大小写查找
    int ignoreCaseIndex = str.indexOf("qt", 0, Qt::CaseInsensitive); // 0
    qDebug() << "忽略大小写查找qt:" << ignoreCaseIndex;

    // 替换所有Qt为Qt6
    QString newStr = str.replace("Qt", "Qt6");
    qDebug() << "替换后:" << newStr;

    // 5. 去除空白
    QString spaceStr = "  Hello   Qt  ";
    qDebug() << "trimmed:" << spaceStr.trimmed(); // "Hello   Qt"
    qDebug() << "simplified:" << spaceStr.simplified(); // "Hello Qt"

    return a.exec();
}

示例代码运行效果展示:QString_demo

在这里插入图片描述

4.2 QVariant

QVariant是Qt的“万能类型”,可以存储几乎所有Qt基础类型(int、QString、QColor、QSize等)和自定义类型,解决了不同类型统一存储的问题(如容器中存储不同类型),补充核心函数原型和自定义类型支持。

核心函数原型
// 构造函数
QVariant::QVariant(); // 空类型
QVariant::QVariant(int val); // 存储int
QVariant::QVariant(const QString &val); // 存储QString
QVariant::QVariant(double val); // 存储double
template <typename T> QVariant::QVariant(const T &val); // 模板构造(支持自定义类型)

// 类型判断
const char *QVariant::typeName() const; // 获取类型名称(如"int"、"QString")
QVariant::Type QVariant::type() const; // 获取类型枚举(如QVariant::Int、QVariant::String)
bool QVariant::canConvert(QMetaType type) const; // 判断是否可转换为指定类型

// 类型转换
int QVariant::toInt(bool *ok = nullptr) const; // 转int
double QVariant::toDouble(bool *ok = nullptr) const; // 转double
QString QVariant::toString() const; // 转QString
template <typename T> T QVariant::value() const; // 模板函数:转指定类型(需注册元类型)

// 自定义类型支持(需注册)
static int qRegisterMetaType<T>(const char *typeName); // 注册自定义类型

代码示例:QVariant存储基础类型+自定义类型
#include <QApplication>
#include <QVariant>
#include <QString>
#include <QColor>
#include <qDebug>

// 自定义类型(需注册元类型)
struct User {
    QString name;
    int age;
    // 必须重载<<运算符,否则qDebug无法输出
    friend QDebug operator<<(QDebug debug, const User &user) {
        debug << "User(name:" << user.name << ", age:" << user.age << ")";
        return debug;
    }
};
// 注册自定义类型(全局作用域)
Q_DECLARE_METATYPE(User)

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

    // 1. 存储基础类型
    QVariant var1(100); // int
    QVariant var2("Qt Variant"); // C字符串→QString
    QVariant var3(3.14); // double
    QVariant var4(QColor(255, 0, 0)); // QColor
    qDebug() << "var1类型:" << var1.typeName() << ",值:" << var1.toInt();
    qDebug() << "var4类型:" << var4.typeName() << ",值:" << var4.value<QColor>().name(); // #ff0000

    // 2. 存储自定义类型
    User user = {"张三", 25};
    QVariant var5 = QVariant::fromValue(user); // 存储自定义类型
    qDebug() << "var5类型:" << var5.typeName() << ",值:" << var5.value<User>();

    // 3. 转换失败处理
    bool ok;
    int val = var4.toInt(&ok); // QColor转int失败
    qDebug() << "QColor转int是否成功:" << ok << ",值:" << val; // ok=false,值=0

    return a.exec();
}

示例代码运行效果展示:QVariant_demo

在这里插入图片描述

五、Qt容器类

Qt提供了一套跨平台的容器类,替代C++标准容器(std::vector/std::map等),核心优势是线程安全(只读操作)、跨平台兼容、接口更易用,补充各容器的核心函数原型和效率优化建议。

5.1 容器类效率对比

容器类 底层实现 时间复杂度(核心操作) 优势场景 劣势场景
QList 数组+指针(预分配内存) 头部/尾部插入:O(1);随机访问:O(1);中间插入:O(n) 高频头部/尾部插入、随机访问、轻量级元素(int/QString) 大对象存储(拷贝成本高)、中间高频插入
QVector 动态数组(连续内存) 随机访问:O(1);尾部插入:O(1)(预分配);中间插入:O(n) 高频随机访问、少插入删除、数值类型存储 头部/中间高频插入
QMap 红黑树(有序) 插入/查找/删除:O(log n) 有序键值对、范围查找(如keys()/values()) 高频插入删除(效率低于QHash)
QHash 哈希表(无序) 插入/查找/删除:平均O(1),最坏O(n) 高频查找、无序键值对、大数据量存储 有序遍历、哈希冲突多的场景

5.2 核心容器用法示例

5.2.1 QList(最常用)
// 核心函数原型
// 构造函数
QList::QList(); // 空列表
QList::QList(const QList &other); // 拷贝构造
QList::QList(std::initializer_list<T> args); // 初始化列表构造(Qt5+)

// 插入/删除
void QList::append(const T &value); // 尾部插入
void QList::prepend(const T &value); // 头部插入
void QList::insert(int i, const T &value); // 索引i插入
T QList::takeAt(int i); // 删除索引i的元素并返回
void QList::removeAt(int i); // 删除索引i的元素(不返回)
void QList::clear(); // 清空列表

// 访问元素
T &QList::operator[](int i); // 读写访问(无越界检查)
const T &QList::at(int i) const; // 只读访问(有越界检查,更安全)
T &QList::first(); // 第一个元素
T &QList::last(); // 最后一个元素

// 查找/遍历
int QList::indexOf(const T &value, int from = 0) const; // 查找元素索引
bool QList::contains(const T &value) const; // 是否包含元素
// 迭代器
typedef typename QList::iterator iterator; // 可读写迭代器
typedef typename QList::const_iterator const_iterator; // 只读迭代器
iterator QList::begin();
iterator QList::end();

5.2.2 QVector
// 核心函数原型
// 构造函数
QVector::QVector(); // 空向量
QVector::QVector(int size); // 指定初始大小(元素默认构造)
QVector::QVector(int size, const T &value); // 指定初始大小和默认值

// 插入/删除
void QVector::append(const T &value); // 尾部插入
void QVector::push_back(const T &value); // 等价于append
void QVector::insert(int i, const T &value); // 索引i插入(效率低)
void QVector::remove(int i, int count = 1); // 从索引i删除count个元素
void QVector::resize(int size); // 调整大小(扩容/缩容)

// 访问元素
T &QVector::operator[](int i); // 读写访问
const T &QVector::at(int i) const; // 只读访问(越界检查)
int QVector::size() const; // 元素数量
int QVector::capacity() const; // 已分配内存的容量
void QVector::reserve(int size); // 预分配容量(减少扩容次数)

5.2.3 QMap与QHash
// QMap核心函数原型
// 构造函数
QMap::QMap(); // 空映射
QMap::QMap(const QMap &other); // 拷贝构造

// 插入/删除
QMap::iterator QMap::insert(const Key &key, const T &value); // 插入键值对(键重复则覆盖)
void QMap::remove(const Key &key); // 删除指定键的元素
void QMap::clear(); // 清空

// 查找/访问
T &QMap::operator[](const Key &key); // 读写访问(键不存在则插入默认值)
const T QMap::value(const Key &key, const T &defaultValue = T()) const; // 只读访问(无则返回默认值)
QMap::iterator QMap::find(const Key &key); // 查找键的迭代器
bool QMap::contains(const Key &key) const; // 是否包含键

// 遍历
QList<Key> QMap::keys() const; // 获取所有键(有序)
QList<T> QMap::values() const; // 获取所有值(有序)

// QHash核心函数原型(与QMap基本一致,差异:无序、哈希表实现)
QHash::QHash();
QHash::iterator QHash::insert(const Key &key, const T &value);
T QHash::value(const Key &key, const T &defaultValue = T()) const;
// 扩展:设置哈希桶数量(优化性能)
void QHash::reserve(int size);
int QHash::bucketCount() const;

5.3Qt容器类综合示例

聚焦最常用 4 种容器,演示增删改查、遍历、存储自定义类

#include <QCoreApplication>
#include <QList>
#include <QVector>
#include <QMap>
#include <QHash>
#include <QString>
#include <QDebug>

// 自定义类(演示容器存储自定义对象)
class Student {
public:
    int id;         // 学号
    QString name;   // 姓名

    // 构造函数
    Student(int i = 0, QString n = "") : id(i), name(n) {}

    // 重载输出符,方便打印
    friend QDebug operator<<(QDebug debug, const Student& s) {
        debug << "Student{ id:" << s.id << ", name:" << s.name << " }";
        return debug;
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    qDebug() << "========== Qt 四大常用容器 综合示例 ==========\n";

    // ==================== 1. QList(最常用动态列表) ====================
    qDebug() << "=== 1. QList 用法 ===";
    QList<Student> stuList;
    // 增
    stuList << Student(101, "张三") << Student(102, "李四");
    stuList.append(Student(103, "王五"));
    // 查:访问、遍历
    qDebug() << "QList第一个元素:" << stuList.first();
    qDebug() << "QList全部元素:";
    for (const auto& s : stuList) qDebug() << s;
    // 改
    stuList[1].name = "李四(修改)";
    // 删
    stuList.removeAt(0);
    qDebug() << "删除后QList:" << stuList << "\n";

    // ==================== 2. QVector(连续内存数组,高效随机访问) ====================
    qDebug() << "=== 2. QVector 用法 ===";
    QVector<int> scoreVec;
    scoreVec << 90 << 85 << 95 << 88;
    // 随机访问(效率最高)
    qDebug() << "QVector索引2的值:" << scoreVec[2];
    // 排序
    std::sort(scoreVec.begin(), scoreVec.end());
    qDebug() << "排序后QVector:" << scoreVec << "\n";

    // ==================== 3. QMap(有序键值对,Key自动排序) ====================
    qDebug() << "=== 3. QMap 用法 ===";
    QMap<int, QString> classMap; // Key:班级号,Value:班级名
    // 增
    classMap[201] = "计算机1班";
    classMap.insert(203, "计算机3班");
    classMap.insert(202, "计算机2班");
    // 自动按键排序
    qDebug() << "QMap(自动排序):" << classMap;
    // 查
    qDebug() << "查找Key=202:" << classMap.value(202) << "\n";

    // ==================== 4. QHash(哈希键值对,查询速度极快,无序) ====================
    qDebug() << "=== 4. QHash 用法 ===";
    QHash<QString, int> scoreHash; // Key:姓名,Value:分数
    scoreHash["张三"] = 92;
    scoreHash["李四"] = 87;
    // 快速查找
    qDebug() << "QHash查找张三分数:" << scoreHash["张三"];
    qDebug() << "QHash所有键:" << scoreHash.keys();

    return a.exec();
}

示例代码运行效果展示:QtContainer_demo

在这里插入图片描述

六、Qt常用工具类

Qt提供了一系列工具类,简化日常开发中的通用操作,补充核心函数原型和进阶用法。

6.1 QSize(尺寸类)

// 构造函数
QSize::QSize(); // (0,0)
QSize::QSize(int width, int height); // 指定宽高

// 尺寸操作
void QSize::setWidth(int width);
void QSize::setHeight(int height);
int QSize::width() const;
int QSize::height() const;
void QSize::scale(int width, int height, Qt::AspectRatioMode mode); // 缩放(保持宽高比)
void QSize::scale(const QSize &size, Qt::AspectRatioMode mode);
bool QSize::isEmpty() const; // 宽/高≤0则为true
bool QSize::isValid() const; // 宽/高≥0则为true

6.2 QDateTime(日期时间类)

// 构造函数
QDateTime::QDateTime(); // 无效时间
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec = Qt::LocalTime); // 日期+时间构造

// 静态函数:获取当前时间
static QDateTime QDateTime::currentDateTime(); // 本地时间
static QDateTime QDateTime::currentDateTimeUtc(); // UTC时间

// 格式化
QString QDateTime::toString(const QString &format) const; // 自定义格式
QString QDateTime::toString(Qt::DateFormat format = Qt::TextDate) const; // 预设格式

// 时间戳转换
qint64 QDateTime::toSecsSinceEpoch() const; // 秒级时间戳(1970-01-01 00:00:00 UTC)
qint64 QDateTime::toMSecsSinceEpoch() const; // 毫秒级时间戳
static QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec = Qt::LocalTime);
static QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec = Qt::LocalTime);

// 时间运算
QDateTime QDateTime::addDays(int days) const; // 加天数
QDateTime QDateTime::addSecs(int secs) const; // 加秒数
int QDateTime::daysTo(const QDateTime &other) const; // 计算与另一个时间的天数差

6.3 QFileInfo(文件信息类)

// 构造函数
QFileInfo::QFileInfo(); // 空文件信息
QFileInfo::QFileInfo(const QString &filePath); // 指定文件路径构造
QFileInfo::QFileInfo(const QFile &file); // 从QFile构造

// 路径信息
QString QFileInfo::fileName() const; // 文件名(含扩展名)
QString QFileInfo::baseName() const; // 基础名(不含扩展名)
QString QFileInfo::suffix() const; // 扩展名(不含.)
QString QFileInfo::filePath() const; // 相对路径
QString QFileInfo::absoluteFilePath() const; // 绝对路径
QString QFileInfo::path() const; // 目录路径(不含文件名)

// 文件属性
qint64 QFileInfo::size() const; // 文件大小(字节)
bool QFileInfo::isFile() const; // 是否为普通文件
bool QFileInfo::isDir() const; // 是否为目录
bool QFileInfo::isSymLink() const; // 是否为符号链接
bool QFileInfo::exists() const; // 文件是否存在
QDateTime QFileInfo::birthTime() const; // 创建时间
QDateTime QFileInfo::lastModified() const; // 最后修改时间
QDateTime QFileInfo::lastRead() const; // 最后访问时间

6.4Qt 常用工具类 综合示例

#include <QCoreApplication>
#include <QString>       // 字符串工具(最核心)
#include <QDateTime>    // 日期时间
#include <QTimer>       // 定时器
#include <QFile>        // 文件读写
#include <QDir>         // 目录操作
#include <QRandomGenerator> // 随机数
#include <QDebug>
#include <QObject>

// 自定义工具类(封装所有Qt常用工具,演示类的用法)
class QtToolDemo : public QObject {
    Q_OBJECT
public:
    explicit QtToolDemo(QObject *parent = nullptr) : QObject(parent) {
        qDebug() << "========== Qt 常用工具类 综合示例 ==========\n";
        testString();      // 1. QString 字符串工具
        testDateTime();    // 2. 日期时间工具
        testRandom();      // 3. 随机数工具
        testFileDir();     // 4. 文件/目录工具
        testTimer();       // 5. 定时器工具
    }

private:
    // 1. QString:Qt最核心字符串工具(替代char*,支持中文、编码、拼接)
    void testString() {
        qDebug() << "=== 1. QString 字符串工具 ===";
        QString str = "Hello Qt";
        // 常用操作:拼接、替换、分割、格式化
        str.append(" 工具类");
        str.replace("Qt", "QT");
        qDebug() << "拼接替换后:" << str;
        qDebug() << "字符串分割:" << str.split(" ");
        qDebug() << "格式化字符串:" << QString("学号:%1,姓名:%2").arg(1001).arg("张三") << "\n";
    }

    // 2. QDateTime:日期、时间、时间差计算
    void testDateTime() {
        qDebug() << "=== 2. QDateTime 日期时间工具 ===";
        QDateTime now = QDateTime::currentDateTime();
        qDebug() << "当前时间:" << now.toString("yyyy-MM-dd hh:mm:ss");
        // 时间计算:加1天
        QDateTime nextDay = now.addDays(1);
        qDebug() << "明天此时:" << nextDay.toString("yyyy-MM-dd") << "\n";
    }

    // 3. QRandomGenerator:安全随机数
    void testRandom() {
        qDebug() << "=== 3. 随机数工具 ===";
        int randNum = QRandomGenerator::global()->bounded(1, 100); // 1-99随机数
        qDebug() << "1-99随机数:" << randNum << "\n";
    }

    // 4. QFile + QDir:文件读写、目录创建
    void testFileDir() {
        qDebug() << "=== 4. 文件/目录工具 ===";
        QDir dir;
        // 创建目录
        if (!dir.exists("TestDir")) dir.mkdir("TestDir");

        // 写入文件
        QFile file("TestDir/test.txt");
        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
            file.write("Qt工具类测试文件\n");
            file.close();
        }

        // 读取文件
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            qDebug() << "文件内容:" << file.readAll();
            file.close();
        }
        qDebug() << "";
    }

    // 5. QTimer:单次/循环定时器
    void testTimer() {
        qDebug() << "=== 5. QTimer 定时器工具 ===";
        QTimer *timer = new QTimer(this);
        // 1秒后执行一次
        timer->singleShot(1000, this, [=]() {
            qDebug() << "定时器触发:1秒倒计时完成!";
        });
    }
};

// 信号槽兼容(Qt类必须)
#include "main.moc"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    // 创建自定义工具类对象,自动运行所有示例
    QtToolDemo demo;
    return a.exec();
}

示例代码运行效果展示:QtUtility_demo

在这里插入图片描述

引用出处

本文核心理论概念、知识点框架参考自爱编程的大丙老师的Qt博客:

  1. Qt 入门
  2. Qt 中的基础数据类型
  3. Qt官方文档:Qt 6.6 Documentation
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐