# study_qt6 **Repository Path**: fangsk/study_qt6 ## Basic Information - **Project Name**: study_qt6 - **Description**: Qt6 学习 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-04-29 - **Last Updated**: 2026-04-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README Qt6学习 ======= # CLion配置Qt开发环境 ```text 1、下载、安装好Qt(这里安装的是 Qt 6.11.0) 2、下载、安装好CLion(这里安装的是 CLion 2025.3.3) 3、在CLion配置CMake时加入以下: -DCMAKE_PREFIX_PATH=D:/dev-tools/Qt/6.11.0/mingw_64 -DCMAKE_CXX_STANDARD=20 -DCMAKE_AUTOMOC=ON -DCMAKE_AUTOUIC=ON -DCMAKE_AUTORCC=ON 注:以上只是大致配置,详细配置请网上查找相关资料!!! ``` # 在CLion开发工具中,qDebug()输出无效及乱码处理 在 main() 方法开头加入以下代码: ```c++ // SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);// 将控制台输出编码设置为UTF-8 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); qputenv("QT_ASSUME_STDERR_HAS_CONSOLE", "1"); qputenv("QT_FORCE_STDERR_LOGGING", "1"); ``` # Qt中的信号与槽 ```text 连接信号与槽:在Qt中,QObject类提供了⼀个静态成员函数connect(),该函数专门用来关联指定的信号函数和槽函数。 connect()函数原型: connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection ) 参数说明: sender:信号的发送者,描述了当前信号由哪个控件发出来。 signal:发送的信号(信号函数),信号的类型。 receiver:信号的接收者,哪个对象(控件)负责处理。 method:接收信号的槽函数,这个对象该怎么处理(要处理对象提供的槽函数)。 type:用于指定关联方式,默认的关联方式为Qt::AutoConnection,通常不需要手动设定。 示例:在窗口中设置一个按钮,当点击“按钮”时关闭“窗口” QPushButton *button = new QPushButton(this); button->setText("关闭"); button->move(200, 200); connect(button, &QPushButton::clicked, this, &QWidget::close); 注:在Qt中,除了通过connect()来连接信号与槽之外,还可以通过函数名字的方式来自动连接! 自动生成槽函数的名称(格式为on_XXX_SSS)有一定的规则,具体规则为: 以on开头,中间使用下划线连接起来。 XXX表示对象名(控件的objectName属性值)。 SSS表示对应的信号,如:on_pushButton_clicked()中的pushButton代表对象名,clicked是对应的信号。 按照这种命名风格定义的槽函数,就会被Qt自动和对应信号进行连接,但是咱们日常写代码的时候,除非是IDE自动生成,否则最好还是不要依赖命名规则,而是显式使用connect()更好。 一方面,显式connect()可以更清晰直观的描述信号和槽的连接关系;另一方面,也防止信号或者槽的名字拼写错误导致连接失效。 使用QtDesigner打开ui文件 -> 选择一个控件(如按钮)然后再右键 -> 转到槽,就可以直接编辑槽函数内容了。 说明:connect()连接信号与槽、emit发送信号的顺序不能颠倒! 原因:先关联信号和槽,一旦检测到信号发射就会立马执行关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应。 注意:发送信号的操作也可以在任意合适的代码中,不一定非得在构造函数中。 ``` # 自定义信号和槽 ```text 在Qt中,允许自定义信号的发送方以及接收方,即可以自定义信号函数和槽函数。但是对于自定义的信号函数和槽函数有⼀定的书写规范。 1、自定义信号函数书写规范 自定义信号函数必须写到"signals"下。 返回值为void,只需要声明,不需要实现。 可以有参数,也可以重载。 2、自定义槽函数书写规范 早期的Qt版本要求槽函数必须写到"public slots"下,但现在高级版本的Qt允许写到类的"public"作用域中或者全局下。 返回值为void,既需要声明,也需要实现。 可以有参数,也可以重载。 发送信号:使用"emit"关键字发送信号,"emit"是⼀个空的宏。"emit"其实是可选的,没有什么含义,只是为了提醒开发人员。 自定义槽函数非常关键,开发中绝大多数情况下都是需要自定义槽函数的,就是用户触发某个操作之后要进行的业务逻辑处理。 相比于自定义槽函数,自定义信号就比较少见,实际开发中很少会需要自定义信号。 由于信号就对应到用户的某个操作,在GUI中用户能够进行哪些操作,其实是可以穷举出来的,而Qt内置的信号基本上就已经覆盖了上述所有操作,因此使用Qt内置的信号就已经足够应付大部分开发场景了。 ``` # 信号与槽重载 以下代码只是片段,仅用于提供思路,不保证能够正确运行!!! ```text // 重载信号1:无参数 void mySignal(); // 重载信号2:int + QString 参数 void mySignal(int num, const QString &str); // 重载槽1:接收无参信号 void mySlot(); // 重载槽2:接收 int+QString 信号(参数类型、顺序必须和信号一致) void mySlot(int num, const QString &str); // connect()连接重载信号与槽的几种方式 // 写法1:函数指针指定重载版本1 connect(_sender, static_cast(&SignalSender::mySignal),// 显式告诉编译器使用无参的mySignal()信号 this, static_cast(&ConnectWidget::mySlot)// 显式告诉编译器使用无参的mySlot()槽 ); connect(_sender, static_cast(&SignalSender::mySignal),// 显式告诉编译器使用带参的mySignal()信号 this, static_cast(&ConnectWidget::mySlot)// 显式告诉编译器使用带参的mySlot()槽 ); // 写法1:函数指针指定重载版本2 void (SignalSender::*signNoParam)() = &SignalSender::mySignal; void (ConnectWidget::*slotNoParam)() = &ConnectWidget::mySlot; connect(_sender, signNoParam, this, slotNoParam); void (SignalSender::*signWithParam)(int, const QString &) = &SignalSender::mySignal; void (ConnectWidget::*slotWithParam)(int, const QString &) = &ConnectWidget::mySlot; connect(_sender, signWithParam, this, slotWithParam); // 写法2:QOverload简化写法,一行搞定 connect(_sender, QOverload<>::of(&SignalSender::mySignal), this, QOverload<>::of(&ConnectWidget::mySlot)); connect(_sender, QOverload::of(&SignalSender::mySignal), this, QOverload::of(&ConnectWidget::mySlot) ); // 写法3:Qt4旧式写法(不推荐,仅兼容),因为无法检测信号或槽函数的名字是否正确 connect(_sender, SIGNAL(mySignal()), this, SLOT(mySlot())); connect(_sender, SIGNAL(mySignal(int, QString)), this, SLOT(mySlot(int, QString))); // 发射信号 emit _sender->mySignal(); emit _sender->mySignal(2026, "Hello Qt,重载信号与槽!"); ``` # QStackedLayout与QStackedWidget的区别 ```text QStackedLayout和QStackedWidget都是Qt中用于管理多个页面(或窗口部件)的类 ,但它们在使用方式和功能上有一些区别。以下是它们的主要区别: 1、使用方式 QStackedLayout: 是一个布局管理器,用于在同一个位置显示多个窗口部件。 通常用于动态管理一组窗口部件,这些窗口部件可以是任意类型的QWidget。 通过QStackedLayout,你可以将多个窗口部件堆叠在一起,并通过索引切换显示的窗口部件。 QStackedWidget: 是一个容器控件,用于在同一个位置显示多个页面。 每个页面是一个QWidget,但QStackedWidget提供了更高级的接口来管理这些页面。 通常用于创建多页的用户界面,例如选项卡或向导。 2、功能 QStackedLayout: 提供了基本的堆叠布局功能。 通过 setCurrentIndex(int index) 或 setCurrentWidget(QWidget *widget) 方法切换显示的窗口部件。 适用于需要动态管理多个窗口部件的场景。 QStackedWidget: 提供了更高级的功能,例如: addWidget(QWidget *widget):添加一个页面。 removeWidget(QWidget *widget):移除一个页面。 setCurrentIndex(int index) 或 setCurrentWidget(QWidget *widget):切换显示的页面。 count():获取页面的数量。 widget(int index):获取指定索引的页面。 适用于需要管理多个页面的场景,例如选项卡或向导。 ``` # Qt打印日志 ```text 日志格式中常用占位符: %{appname}:应用程序的名称(QcoreApplication::applicationName() %{category}:日志所处的领域 %{file}:打印该日志的文件路径 %{function}:打印日志的函数 %{line}:打印日志在文件中的行数 %[message}:日志的内容 %{pid}:打印日志的程序的PID(QCApplication::applicationPid()) %{threadid}:打印日志的线程ID %{qthreadptr}:打印日志的线程指针 %{type}:日志级别(debug、critical、fatal) %{time process}:日志发生时程序启动了多久 %{time boot}:日志发生时系统启动了多久 %{time [format]}:以固定时间格式输出日志打印的时间,默认为QIs0Date格式 qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type}]: %{message}"); qputenv("QT_MESSAGE_PATTERN", QByteArray("%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type}]: %{message}")); 条件模式(如只在debug级别下输出文件名、函数名、行号): qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type}]%{if-debug} %{file} %{function}(%{line})%{endif}: %{message}"); qputenv("QT_MESSAGE_PATTERN", QByteArray("%{time yyyy-MM-dd hh:mm:ss.zzz} [%{type}]%{if-debug} %{file} %{function}(%{line})%{endif}: %{message}")); 注意:如果同时调用了qSetMessagePattern()方法、设置了QT_MESSAGE_PATTERN环境变量,则环境变量的优先级更高。 让日志输出到文件中:qInstallMessageHandler(logMessageHandler); 注意:在Release模式下,文件名、函数名、行号获取不到,需要在CMakeLists.txt文件中添加编译时宏QT_MESSAGELOGCONTEXT: 方法1(全局范围内可用):add_definitions(-DQT_MESSAGELOGCONTEXT) 方法2(目标范围内可用):target_compile_definitions(你的可执行程序名称 PRIVATE QT_MESSAGELOGCONTEXT) ``` # 如何在CMakeLists.txt中输出信息 ```text 基本语法:message([消息模式说明] "消息内容 ${变量名}") 消息模式说明: - STATUS:默认模式,输出普通状态信息,通常显示在构建过程中 - WARNING:输出警告信息,会以黄色显示 - AUTHOR_WARNING:仅在开发模式下显示的警告 - SEND_ERROR:输出错误信息,但继续执行构建 - FATAL_ERROR:输出致命错误信息,终止构建 - DEPRECATION:输出弃用警告 示例-输出单个变量: message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") message(STATUS "CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}") 示例-输出多个变量: message(STATUS "Qt安装路径: ${QT_INSTALL_PATH}") message(STATUS "调试后缀: ${DEBUG_SUFFIX}") 示例-输出路径是否存在: if (EXISTS "${QT_INSTALL_PATH}/bin") message(STATUS "Qt bin 目录存在: ${QT_INSTALL_PATH}/bin") else() message(WARNING "Qt bin 目录不存在: ${QT_INSTALL_PATH}/bin") endif() 示例-输出列表变量: message(STATUS "Qt组件: ${Qt5_COMPONENTS}") 示例: if (MSVC) message(STATUS "使用MSVC编译器") elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "使用GCC/MinGW编译器") endif () message(STATUS "系统名称:${CMAKE_SYSTEM_NAME},构建生成器:${CMAKE_GENERATOR},编译器版本:${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Qt安装路径:${QT_INSTALL_PATH},构建类型:${CMAKE_BUILD_TYPE},调试后缀:${DEBUG_SUFFIX}") ``` # 编译MySQL驱动(使用qmake) ```text 1、获取Qt源码 安装目录(目录/Qt/5.15.2/Src/qtbase/src/plugins/sqldrivers/mysql)下的源码 或https://github.com/qt/qtbase.git指定分支的源码 2、修改配置文件 修改mysql.pro: 注释:QMAKE_USE += mysql 增加:INCLUDEPATH += "D:/database/mysql-8.0.30-winx64/include" LIBS += -L"D:/database/mysql-8.0.30-winx64/lib" -llibmysql 修改上一级目录中的qsqldriverbase.pri: 注释:include($$shadowed($$PWD)/qtsqldrivers-config.pri) 增加:include(./configure.pri) 3、执行编译、安装 打开Qt自带的MinGW命令行工具:开始菜单 → Qt → Qt 5.15.2 (MinGW 8.1.0 64-bit) 进入mysql源码目录,依次执行:qmake、mingw32-make、mingw32-make install 执行成功后,在 目录/Qt/5.15.2/mingw81_64/plugins/sqldrivers 下会多出qsqlmysql.dll、qsqlmysql.dll.debug两个文件 4、测试 到mysql安装目录下,将 libmysql.dll、libcrypto-1_1-x64.dll、libssl-1_1-x64.dll三个文件复制到和exe同级目录 或:复制到 目录/Qt/5.15.2/mingw81_64/bin 下,但这种方式需要配置环境变量 ``` # 编译MySQL驱动(使用cmake) ```text 1、获取Qt源码 安装目录(目录/Qt/6.11.0/Src/qtbase/src/plugins/sqldrivers)下的源码 或https://github.com/qt/qtbase.git指定分支的源码 2、修改配置文件 修改CMakeLists.txt: 增加:SET(FEATURE_sql_mysql ON) SET(MySQL_INCLUDE_DIR "D:/database/mysql-8.0.30-winx64/include") SET(MySQL_LIBRARY "D:/database/mysql-8.0.30-winx64/lib/libmysql.dll") 3、执行编译、安装 使用 qtcreator 打开 sqldrivers 目录下的 CMakeLists.txt 打开项目,进行编译。根据是否报错,注释 CMakeLists.txt 里面的 if(QT_FEATURE_sql_sqlite) add_subdirectory(sqlite) endif() if(QT_FEATURE_sql_odbc) add_subdirectory(odbc) endif() 执行成功后,在编译目录下会多出qsqlmysql.dll、qsqlmysql.debug两个文件,将其复制到 目录/Qt/6.11.0/mingw81_64/bin。 4、测试 到mysql安装目录下,将 libmysql.dll、libcrypto-1_1-x64.dll、libssl-1_1-x64.dll三个文件复制到和exe同级目录 或:复制到 目录/Qt/6.11.0/mingw81_64/plugins/sqldrivers 下,但这种方式需要配置环境变量 ``` # 示例 ```text 内容 ``` # 参考项目 - [Qt组件:数据库](https://github.com/qt/qtbase.git) - [Qt组件:MQTT](https://github.com/qt/qtmqtt.git) - [中国象棋](https://github.com/XMuli/ChineseChess.git) - [QtExamples](https://gitee.com/XMuli/QtExamples.git) - [QT电子相册](https://gitee.com/suhuamo/qt-electronic-photo-album.git) # 参考资料 - [爱编程的大丙:Qt教程](https://www.subingwen.cn/qt) - [QT6搭建和使用MQTT](https://blog.csdn.net/qq_64171874/article/details/148279527) - [使用QtCreator构建项目与Qt底层机制的深度解析](https://cloud.tencent.com/developer/article/2617195) - [QTreeWidget详解](https://cloud.tencent.com/developer/article/2158245) - [Qt窗口组成和初识对话框](https://cloud.tencent.com/developer/article/2525805) - [QT界面的美容院--QSS](https://cloud.tencent.com/developer/article/2513965) - [QT 的窗口坐标&信号与槽](https://cloud.tencent.com/developer/article/2485638) - [QT-布局管理器(Box,Grid,Form,Stacked)](https://cloud.tencent.com/developer/article/1137388) - [QT-布局管理器](https://blog.csdn.net/qq_59805046/article/details/150703351) - [Qt文件和多线程](https://cloud.tencent.com/developer/article/2464544) - [QT控件--显示类](https://cloud.tencent.com/developer/article/2491930) - [QT控件--输入类](https://cloud.tencent.com/developer/article/2492410) - [QT控件--多元素类、容器类、布局类](https://cloud.tencent.com/developer/article/2494348) - [QT控件--QMainWindow窗口](https://cloud.tencent.com/developer/article/2497171) - [QT控件--Dialog对话框](https://cloud.tencent.com/developer/article/2500746) - [QT事件系统入门——QEvent基础与示例](https://cloud.tencent.com/developer/article/2504687) - [QT文件--QFile基础和示例](https://cloud.tencent.com/developer/article/2506706) - [一文学会QT多线程(QThread )](https://cloud.tencent.com/developer/article/2507357) - [基于Qt的UI设计示例项目](https://github.com/YYC572652645/QCoolPage.git) - [从零开始的Qt开发指南:合集](https://cloud.tencent.com/developer/column/106863?tag=10224) - [从零开始的Qt开发指南:(三)信号与槽的概念与使用](https://cloud.tencent.com/developer/article/2617222) - [从零开始的Qt开发指南:(四)Qt信号与槽拓展:从自定义到连接方式,带你彻底掌握信号与槽的本质](https://cloud.tencent.com/developer/article/2617235) - [从零开始的Qt开发指南:(五)Qt常用控件之QWidget(上):解锁Qt界面开发的核心基石](https://cloud.tencent.com/developer/article/2617259) - [从零开始的Qt开发指南:(六)Qt常用控件之QWidget(下):从交互细节到颜值定制,打造专业级界面](https://cloud.tencent.com/developer/article/2617261) - [从零开始的Qt开发指南:(七)Qt常用控件之按钮类控件深度解析:从QPushButton到单选/复选的实战指南](https://cloud.tencent.com/developer/article/2617267) - [Qt布局管理详解(5种布局控件)](https://c.biancheng.net/view/9422.html) - [QStackedLayout、QStackedWidget二者的区别](https://blog.csdn.net/m0_55576290/article/details/147797090) - [Qt学习](https://juejin.cn/column/7497558282410147859) - [走进Qt--信号与槽机制详解与实战](https://juejin.cn/post/7498280250553204748) - [走进Qt--QWidget基类详解](https://juejin.cn/post/7498535220783792191) - [走进Qt--常用控件1&布局](https://juejin.cn/post/7498638250136436790) - [走进Qt--常用控件QTabWidget&QListWidget &QScrollArea](https://juejin.cn/post/7498988293208965174) - [走进Qt--Qt常用输入控件详解](https://juejin.cn/post/7501621602345205796) - [走进Qt--QProgressBar与QTableWidget应用](https://juejin.cn/post/7502010491005632566) - [走进Qt--事件处理解析](https://juejin.cn/post/7503136487376666643) - [走进Qt--无边框窗口实现](https://juejin.cn/post/7503841742896431116) - [QT-事件](https://blog.csdn.net/qq_59805046/article/details/151176695) - [Qt事件分发器&事件过滤器](https://cloud.tencent.com/developer/article/2439572) - [Qt事件进阶:定时器、事件分发器与事件过滤器的实战](https://cloud.tencent.com/developer/article/2617376) - [Qt系统(三)->事件过滤器](https://blog.csdn.net/weixin_74809706/article/details/156342234) - [Qt中的互斥锁(QMutex和QMutexLocker)](https://blog.csdn.net/m0_60529319/article/details/130727677) - [Qt网络编程:QTcpSocket与QTcpServer使用详解](https://telepan.blog.csdn.net/article/details/151586570) - [Qt线程同步机制:互斥锁、信号量、条件变量、读写锁](https://blog.csdn.net/weixin_50873490/article/details/140275705) - [详细介绍 QT的各种锁机制](https://openharmonycrossplatform.csdn.net/694108b796fa167eeece9ad0.html) - [Qt开发:运用QJSON模块解析数据](https://cloud.tencent.com/developer/article/2384559) - [Qt开发:TreeWidget树形选择组件](https://cloud.tencent.com.cn/developer/article/2372293) - [Qt基于TCP实现客户端与服务端的连接](https://www.jb51.net/article/260202.htm) - []()