ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

QT入门实战:从环境搭建到信号槽、多线程与打包发布

QT入门实战:从环境搭建到信号槽、多线程与打包发布 QT这套跨平台的C图形界面框架这几年在工控上位机、桌面工具、嵌入式设备里出现的频率越来越高。我自己就是从MFC转过来的人最初觉得QT无非是多了一些现成控件可真把项目做完一轮才发现QT最值钱的部分是它的事件模型和跨平台封装。这篇是我的QT学习系列第1篇主要写给三种人准备接触QT开发的后端或嵌入式工程师、正在拿QT做课程设计或毕设的学生、以及想把手头工具软件重新整理一遍的独立开发者。内容会覆盖从环境搭建到第一个可运行窗口再到信号槽、多线程、打包发布和常见崩溃排查都是这阵子我实际踩过的路线希望能帮刚起步的人少走点弯路。1. 为什么学QT先搞清楚这是什么东西1.1 QT的本质一套C图形界面框架但远不止图形界面很多人一说QT第一反应是“C写界面”。这话对但不完整。QT的核心其实是一套完整的应用程序开发框架除了大家熟悉的Widgets控件库它还提供了网络、数据库、XML/JSON解析、多线程、OpenGL集成、多媒体、WebEngine等一系列模块。换句话说你用QT不只是画窗口、放按钮它是能支撑起一个完整桌面产品或嵌入式终端应用的基础设施。我见过不少朋友拿QT做工业软件选型的时候对比MFC、WPF、GTK最后选QT的原因通常是跨平台。MFC太老界面风格停留在上个时代而且只认WindowsWPF漂亮、绑定了Windows生态但脱离平台就比较吃力GTK在Linux下配置环境要费一些功夫Windows下的发布体验也不省心。QT在这方面一个工程跑多个平台桌面、嵌入式、甚至部分移动端都能覆盖。工业现场最常见的做法就是Windows上位机一套代码Linux工控机一套代码核心模块几乎不用动。所以QT到底是什么它就是“桌面应用里的瑞士军刀”——功能覆盖广、开发效率高、跨平台能力强。做上位机、仪器仪表、边缘计算盒子界面的时候QT基本是绕不过去的一项技能。再加上QT5时代整个社区积累了海量Demo和问答遇到问题搜一圈答案大多能落地这对新手特别友好。1.2 适合谁学、主要解决什么问题我个人的观察现在学习QT的人大概分成三类。第一类是嵌入式或单片机方向的同学。写完了驱动、调通了协议需要一个上位机来调试数据。用QT做个串口助手、网络调试工具再配几张曲线图比用现成工具灵活得多。热词里出现的“qt 做嵌入式”“qt交叉编译环境”“qt 调用halcon”、“qt 调用proj”这类需求其实都是这一类——QT只是壳核心是嵌入式和算法库的交互。第二类是工业软件、桌面工具开发者。比如做设备控制、数据采集、机器视觉上位机的工程师。这类项目硬件交互多界面逻辑复杂还常常要求长期稳定运行。QT的信号槽机制在这种场景下非常合适UI事件和业务处理能解耦得很干净。第三类比较杂有做课程设计的学生有想从C#、Python转过来的桌面应用开发者。这些人通常已经有编程基础缺的只是一套QT生态的完整认知知道什么东西该去哪里查、报错之后第一步先怀疑谁。不管你是哪一类入门QT必须跨过几道坎第一是环境搭建第二是信号槽这套事件驱动的思维第三是编译打包。这三步走通后面基本都是堆功能了。下面我就按这个顺序聊。2. 环境搭建装对版本等于省下一周时间2.1 下载与安装为什么很多教程推荐QT 5.15.2关于QT版本不同时期的答案不太一样。现在QT6已经出了好几年商用上QT6是趋势但大量老工程、第三方库、博客教程还停留在QT5。我这次选的是QT 5.15.2。原因有几个第一5.15是QT5的最后一个LTS版本官方维护周期长稳定性和安全性有保障第二搜索引擎里你能找到的多数教程、插件、问题解答跑在5.15上基本不会偏差太多第三对新手来说5.15的在线资料密度远大于6.x碰到一个报错能搜到一堆解决方案。下载方式上Qt开源版从官网走维护工具会比较慢很多人在这一步就卡住了。热词里的“qt安装教程”“qt下载”指向的其实就是这些操作打开Qt官网下载页面选择开源社区版注册账号、下载在线安装器。我个人更推荐直接下载离线安装包省去在线安装器反复拉取文件的过程。具体版本选“qt-opensource-windows-x86-64-5.15.2.exe”这种命名格式的包体积比较大但一次性装完整。组件选择时需要注意两件事一是安装目录不要带空格和中文二是勾选组件时要把编译器对应的套件选清楚。比如你的Windows上用Visual Studio 2019那就选MSVC 2019 64-bit如果你想用一套轻量的开源编译器就选MinGW 7.3.0。这俩不要混后面出问题九成都在这里。2.2 官网太慢国内镜像站下载的正确姿势如果你不想在官网下载页等半天国内镜像站是很好的选择。清华源、中科大源都有QT的完整归档路径一般是 /qt/ 或 /qtproject/ 下的某级目录里。直接找到对应版本号、对应操作系统的安装包下载速度能跑满带宽比在线安装器体感快一个量级。这里重点提醒一下版本号后缀的问题。你在镜像站会看到类似的包名qt-opensource-windows-x86-64-5.15.2_msvc2019_64.iso 或者 .exe。其中的 msvc2019_64 表示这是用MSVC 2019 64位编译器构建的版本。下载的时候必须清楚自己机器上有哪个编译器否则后面建Kit套件时会发现“没有可用编译器”的尴尬局面。另外镜像站下载的包可能是 .iso 格式Windows下解压或挂载即可。安装界面选组件时如果只需要桌面Widgets开发勾选“qt5.15.2 MSVC 2019 64-bit”以及“Qt Charts”“Qt Data Visualization”这类常用附加模块就够了QML那套暂时用不到可以关掉能省不少磁盘空间。2.3 Ubuntu 20.04下搭建QT交叉编译环境的要点“交叉编译”这个词对做嵌入式、做边缘计算盒子的人来说不陌生。意思是在X86的宿主机上编译出ARM架构目标板能运行的程序。QT的交叉编译环境搭建本质上是三件事交叉编译器、交叉编译的QT库、构建系统的路径配置。在Ubuntu 20.04上先用apt把交叉编译器装好。比如目标平台是ARM64就安装 gcc-aarch64-linux-gnu 和 g-aarch64-linux-gnu。下一步是准备目标平台的QT库两种方式一是用apt安装对应架构的qtbase5-dev等包二是从QT源码自行交叉编译。新手我更建议直接用apt省事很多sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu sudo apt install qtbase5-dev装好之后在Qt Creator里手动添加一个Kit编译器选择AArch64的gcc和gqmake选择目标平台的qmake路径。新建Kit时注意CMake或qmake的路径要指向目标环境里那一个不要指错成宿主机的。第一次编译出现“cannot find -lGL”这类报错通常是OpenGL开发库缺失安装libgl1-mesa-dev即可。这个过程中最容易踩的坑其实是“Qt版本”和“编译器”的交叉组合不匹配比如用x86的qmake配ARM编译器编译出来的程序直接报格式错误。碰到这种情况回到Kit设置里逐项检查基本能定位。2.4 不止Qt CreatorVS Code、CLion、CodeBlocks都可以跑QT不少人不喜欢用Qt Creator这完全正常。我就是用CLion做主力写QT的人。关键是你要理解QT工程的本质它最终靠的是qmake或CMake来组织构建IDE只是壳。VS Code配置QT先安装C/C扩展和Qt Tools扩展。Qt Tools里要设置Qt的bin路径然后它就能帮你自动生成tasks.json、launch.json。创建工程建议直接用CMake工程在CMakeLists.txt里调用 find_package(Qt5 REQUIRED COMPONENTS Widgets) 这样的写法比写.pro文件在VSCode里更顺。CLion跑QT基本零障碍它天生支持CMake。你只需要在Toolchains里选择好MSVC或MinGW/GCC然后让CMake找到QT路径。需要注意Windows上CLion MSVC编译器时需要提前安装“Visual Studio Build Tools”否则找不到cl.exe。CodeBlocks相对古老一些也可以用但配置路径繁琐除非是自己很熟的编辑器否则我不推荐新手从这里起步。3. 从零跑通第一个窗口工程结构、UI与第一屏应用3.1 用Qt Creator创建项目的完整流程环境装好后第一件事是建一个能跑的窗口。Qt Creator里新建项目选择“Application Qt Widgets Application”然后选构建套件——这一步要确保你刚才安装的QT版本和编译器都呈现在Kit列表里。新建工程时会让选基类QMainWindow、QWidget、QDialog。三者的区别并不复杂QMainWindow是带菜单栏、工具栏、状态栏的主窗口QDialog是模态对话框适合做弹窗QWidget是空白的通用窗口什么都能往上放。第一个项目我建议选QMainWindow因为后面加菜单、工具栏都方便。生成后的工程目录里会有几个关键文件main.cpp、mainwindow.cpp、mainwindow.h、mainwindow.ui、项目名.pro。从这一刻起你要理解一件事按F5能运行出空窗口不代表你懂QT这只是环境配置正确的信号。真正的入口是main函数里那句 QApplication a(argc, argv); 窗口对象交给 a.exec() 进入事件循环程序才会开始响应鼠标和键盘。这个事件循环的概念后面解释信号槽的时候非常关键。3.2 .pro文件里隐藏的信息.pro文件是qmake构建系统的心脏。打开看一眼内容看起来很少但每一行都有含义。QT core gui 表示需要核心模块和GUI模块大于QT4版本时追加QT widgets这是QT5时代分离出来的控件模块不加的话连QPushButton都用不了。如果你后面要加网络、串口、图表就在.pro文件里增加对应的模块声明QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets QT network serialport charts TARGET MyApp TEMPLATE app SOURCES main.cpp\ mainwindow.cpp HEADERS mainwindow.h FORMS mainwindow.uiTARGET是生成的可执行文件名字TEMPLATE是构建目标类型。app就是可执行程序lib表示库。学QT的过程里仔细读.pro文件能让你迅速摸清工程依赖遇到编译报错“未定义的引用”时第一反应就应该是某个QT模块没加进.pro。3.3 UI设计器与.ui文件的生成逻辑Qt Creator自带的设计器Qt Designer支持拖拽控件到主窗口然后通过布局管理器自动排列。很多新手只会拖不理解这背后发生了什么。拖出来的界面会被保存到mainwindow.ui文件里这个文件本质是XML格式。编译时有个叫uic的工具会把.ui文件转换成ui_mainwindow.h头文件里面自动生成一个setupUi函数。所以你在代码里看到的 ui-setupUi(this) 实际上就是把你拖出来的控件“安装”到当前窗口上。UI设计器里两个容易被忽略的点一是布局管理。放完控件一定要选中所有控件然后点击“栅格布局”或“垂直/水平布局”按钮否则窗口一放大控件还是钉在原处。二是添加间隔空白Spacer。用弹簧来控制布局间距离这是让窗口在不同分辨率下不失调的最基础手段。另外不要手动修改构建生成的ui_xxx.h文件。机器生成的文件重新编译就会被覆盖。如果你要做的控件逻辑比较复杂可以直接动手写代码没必要依赖设计器。“qt界面设计”的核心思路是用布局器而不是用绝对坐标这一点越早养成越好。3.4 第一个有实际意义的小功能用QFileInfo读取文件信息为了不让你觉得QT只是个空窗口玩具我建议第一个小功能做成“读取文件信息”。这也是热词里“qt获取文件信息”的实际需求。逻辑很简单一个按钮触发文件选择对话框然后展示文件的名称、大小、后缀和最后修改时间。关键代码如下#include QFileDialog #include QFileInfo #include QDebug void MainWindow::on_btnChooseFile_clicked() { QString filePath QFileDialog::getOpenFileName(this, 选择文件); QFileInfo info(filePath); if (!info.exists()) { qDebug() 文件不存在; return; } qDebug() 文件名: info.fileName() 路径: info.absoluteFilePath() 大小: info.size() 后缀: info.suffix() 修改时间: info.lastModified().toString(yyyy-MM-dd HH:mm:ss); }如果你需要列出目录下的所有子目录用QDir的entryInfoList并过滤标志位。这是热词里“dir.entryinfolist”对应的标准写法QDir dir(.); QFileInfoList list dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); for (const QFileInfo fi : list) { qDebug() fi.absoluteFilePath(); }QDir::NoDotAndDotDot这个过滤标志的作用是去掉“.”和“..”两个特殊目录。很多新版踩的坑就是忘记加这个标志遍历目录时多出两个莫名其妙的项。4. 信号槽机制理解QT的“消息总线”4.1 信号槽是QT的神经系统QT和传统API回调最大的不同就是它提供了信号槽机制。用一个生活化的例子解释你在手机上点了“立即支付”按钮按钮发出“我点击了”的clicked信号然后支付模块的某个槽函数被自动调用完成扣款流程。按钮和支付模块互相不认识它们之间通过信号和槽连接起来代码解耦得干干净净。在代码里连接是这样写的connect(ui-btnPay, QPushButton::clicked, this, MainWindow::onPay);第1个参数是信号发送者第2个参数是信号第3个参数是接收者第4个参数是槽函数。QT5之后推荐用函数指针写法编译期就能检查类型错误。如果第4个参数写错会有编译错误。相比早期QT4那种传字符串宏的写法这种写法安全很多。信号槽能实现一对一、一对多、多对一连接。一个信号可以连接多个槽多个信号也可以连到同一个槽。这也是QT界面和业务协作灵活的根本原因。新手需要花几天时间彻底接受这个异步思维界面只管发信号业务模块只管接信号别把逻辑全堆在按钮点击函数里。4.2 多参数、Lambda表达式与自定义信号信号槽连接的槽函数不一定要写在头文件里QT5还支持直接用Lambda表达式connect(ui-btnSend, QPushButton::clicked, this, [this](){ QString text ui-lineEdit-text(); emit mySignal(text); });自定义信号要在类的signals区域声明例如class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent nullptr); signals: void dataReady(const QString data); };自定义信号不需要写实现只需要在合适的地方调用emit dataReady(text)。emit不是函数调用它只是一个触发关键字真正的工作由元对象系统在内部完成。这也是QT代码里最常见的“语法糖”之一。4.3 槽函数返回值这个坑很多人踩热词里有一条“qt 槽函数 返回值”说明这问题很真实。很多人第一次遇到就懵了我在槽函数里写了return外面怎么拿不到原因很简单信号槽调用不是普通函数调用调用者发出信号后槽函数是通过元对象系统被异步触发的返回值无处安放。举个例子connect(button, QPushButton::clicked, this, []() - int { return 123; });这个return 123没有任何接收者根本拿不到。连接的本质是“通知”不是“询问”。那如果确实想让槽函数返回结果怎么办实际工程中常用的做法有这么几种第一种通过引用参数修改外部变量。槽函数声明时带一个引用或指针参数调用信号前先准备好容器void MainWindow::collectResult(int result) { result 123; } // 连接时用lambda包装 connect(button, QPushButton::clicked, this, [this]() { int result 0; collectResult(result); qDebug() result; });第二种通过信号传递结果。槽函数处理完成后emit一个新的“结果信号”拿到结果的地方再去监听这个信号。这是最符合QT习惯的做法。第三种用QMetaObject::invokeMethod进行阻塞调用。这种方法能拿到一个bool返回值但只表示调用是否成功不是槽函数的业务返回值。真要取业务结果还是回到前两种方案。4.4 Auto、DirectConnection与QueuedConnection连接类型别忽视connect函数的第5个参数可以指定连接类型默认是Qt::AutoConnection。它的规则是如果发送者和接收者在同一个线程使用DirectConnection相当于直接函数调用如果跨线程使用QueuedConnection把调用包装成事件发到接收者所在线程。这里敲黑板的原因是因为后面多线程串口接收能不能正确刷新界面就看QueuedConnection有没有生效。DirectConnection跨线程直接调用槽函数是危险操作。因为接收者所在线程可能正在处理别的事件直接调它的槽函数轻则数据竞争重则崩溃。如果你在代码里用了跨线程的connect又没有指定Qt::QueuedConnection那么AutoConnection会自动处理。但是如果你connect时强制用了Qt::DirectConnection跨线程就成了定时炸弹。5. 高频泥潭线程、串口与打包发布5.1 串口接收必须放线程一个真实需求热词里“qt如何把modbus串口接收放到线程”是个很典型的工控需求。项目初期的做法可能是这样主线程创建一个QSerialPort每次数据到达后触发readyRead信号在槽函数里直接处理。如果只是低速读写界面还能扛住。可一旦数据量大、或者你的处理逻辑里有耗时运算UI就会开始卡顿。因为你一直在处理串口逻辑根本没时间去响应界面重绘。更正确的做法是数据接收放到子线程。QT对线程的支持不是直接继承QThread更推荐的方式是定义一个QObject的Worker类把串口对象放在这个Worker里然后通过moveToThread把Worker整个挪到子线程。这样串口的readyRead信号和槽函数都会自动在子线程执行UI线程保持通畅。一个最小骨架如下class SerialWorker : public QObject { Q_OBJECT public slots: void openPort(const QString portName) { m_serial new QSerialPort(portName); connect(m_serial, QSerialPort::readyRead, this, SerialWorker::readData); } void readData() { QByteArray data m_serial-readAll(); emit dataArrived(data); } signals: void dataArrived(const QByteArray data); private: QSerialPort *m_serial nullptr; };然后在主线程里SerialWorker *worker new SerialWorker; QThread *thread new QThread; worker-moveToThread(thread); connect(thread, QThread::started, worker, SerialWorker::openPort); connect(worker, SerialWorker::dataArrived, this, [this](const QByteArray data){ // 更新界面注意槽函数在主线程执行 }); thread-start();这个模式的关键在于所有和串口直接交互的槽函数都在worker类里moveToThread之后串口对象的事件循环就跑在子线程中。如果你在主线程里直接调用uart读接口大概率会不断报QObject::killTimer定时器初始化失败之类的错误。只要理解事件循环跟着线程走这个坑就不会再踩第二次。5.2 发布软件windeployqt和你必须带的DLLQT程序的发布是一个最容易让新手崩溃的环节。开发环境里按下F5跑得飞起把exe复制到别的电脑上双击提示“无法启动此程序因为计算机中丢失Qt5Core.dll”。这不是QT特有的问题是动态库依赖的常规操作只是QT依赖的库比较多手工拷贝容易漏。正确的做法是使用QT自带的部署工具。Windows下先打开“Qt 5.15.2 (MSVC 2019 64-bit)”这个命令行注意一定要选择和你编译时相同的编译器环境然后进入你的exe所在目录执行windeployqt MyApp.exe这个工具会扫描exe的导入表自动把Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll等基础DLL复制过来还会自动生成platforms子目录并放入qwindows.dll。缺了platforms目录里的qwindows.dll启动时就会报“could not find or load the Qt platform plugin windows”这也就是热词里qt_qpa_platform_plugin_path问题的直接原因。部署完成后检查一下目录结构一般至少要有exe文件、platforms文件夹、几个核心DLL。如果用了serialport、charts等模块确认相应的DLL是否也进来了。没有的话从QT安装目录的bin文件夹里手动拷贝进去。还有一点经验发布时尽量用release版本别拿debug版本去发布。debug版本的DLL体积大且慢如果拷错了程序会在别的机器上出现缺少MSVCPD.dll这类调试库。5.3 卸载QT与清理环境残留不想要了或者装坏了想重装卸载QT也有讲究。Windows下用安装目录里的MaintenanceTool.exe是最正规的方式能按组件卸载不会留下太多垃圾。如果直接删文件夹往往会在注册表和环境变量里留下一堆残留比如你以前设置的QT_QPA_PLATFORM_PLUGIN_PATH变量可能继续影响编译运行。清理环境这件事热词里出现“linux找qt路径”其实就是典型的残留问题。Linux下用几个命令就能定位QT的安装位置which qmake qmake -v find /usr -name qmake 2/dev/nullUbuntu下如果是通过官方包管理器安装的可以用dpkg -L qt5-qmake之类命令列出文件清单。定位到路径后要么主动设置QT_ROOT环境变量要么在构建脚本里用完整路径调用qmake。很多“编译时一切正常运行时找不到Qt路径”的问题根本原因就是PATH里找不到qmake或qmake版本对应错误。先which再定位版本是解决这类问题最快的路径。6. 常见问题排查实录6.1 qt_qpa_platform_plugin_path报错的真相热词里那条路径本身就已经说明了问题你手动把QT_PLATFORM_PLUGIN的平台插件路径指向了QT安装目录的platforms文件夹。这在开发环境里没问题但发布后换一台没有QT的机器这个路径就失效了。实际排查顺序我建议这样走第一步确认exe同级的platforms目录里有没有qwindows.dll。很多情况下你只是把exe单独拷走了。第二步确认你把DLL和编译器版本配对了。MSVC编译的exe拷了MinGW的DLL启动时可能直接崩溃而不是友好提示。第三步确认系统的PATH环境变量里没有乱七八糟的QT路径。如果用户机器上以前装过别的QT版本PATH一旦指错程序加载的DLL顺序就乱了。不要轻易在别人的机器上设置QT_QPA_PLATFORM_PLUGIN_PATH环境变量指向开发机上的QT目录。那是治标不治本平台插件路径该由应用自身目录来兜底。6.2 QT程序崩溃的排查思路QT程序崩溃通常绕不开这几个原因对象生命周期管理混乱、跨线程访问UI、空指针解引用。生命周期问题最典型的是QObject父子关系。QObject构造函数可以传parentparent在析构时会负责delete所有子对象。如果你手动new了一个QObject又用parent管理再手动delete一次就会出现double free。反过来如果你没有parent又忘了delete那就是内存泄漏。我的习惯是界面上new的控件都指定parent剩下业务对象尽量用对象成员或智能指针避免裸指针。跨线程访问UI也是高发崩溃点。在子线程里直接调用ui控件的text()、setText()轻则界面闪烁重则直接崩。正确做法是子线程发信号主线程的槽函数里更新UI。如果你的项目已经出现跨线程改UI的习惯建议给这类函数顶部直接加一个断言检查Q_ASSERT(QThread::currentThread() this-thread())让错误尽早暴露。如果崩溃点完全看不出规律先用调试器看调用堆栈。Windows下用Visual Studio的调试器或者Qt Creator自带的调试器可以直接定位崩溃行。很多新手遇到崩溃第一反应是加日志但QT的Release版日志本身就可能被优化掉。有条件就开Debug版把Q_ASSERT、qDebug全部打开问题定位能快一倍。6.3 外部库调用proj、halcon这样的大库怎么接进工程“qt 调用proj”、“qt怎么调用halcon”这类问题本质上都是同一个问题QT如何链接第三方库。步骤并不复杂但细节非常多。第一步确认库的版本和编译器匹配。比如proj库有官方Windows二进制包要选择对应MSVC 2019 64位版本。如果你手里只有MinGW编译的QT却用一个MSVC编译的静态库链接时必然报“undefined reference”。这一步踩坑的比例非常高。第二步在工程文件里声明头文件和库的路径。qmake工程这样写INCLUDEPATH C:/libs/proj-9.0.0/include LIBS -LC:/libs/proj-9.0.0/lib -lprojCMake工程这样写find_package(PROJ REQUIRED) target_link_libraries(MyApp PRIVATE PROJ::proj)第三步把DLL放到运行目录。动态库的DLL文件必须能被程序在运行时找到通常放在exe同级目录。缺DLL时的报错可能千奇百怪有的是启动闪退有的是启动后功能不可用。可以先下载一个Dependencies工具直接把exe拖进去看依赖项一目了然。以halcon这类视觉库为例它的接口一般是标准C或C头文件和DLL拷贝好后在QT里调用与在Visual Studio里调用方法几乎一致。关键就是别让编译器和库的发型不匹配x86的QT配x64库必崩MSVC的QT配MinGW库也必崩。6.4 Kotlin等混合开发的配置问题这部分算额外补充吧。如果你不是纯QT开发而是把QT作为一个显示组件嵌入到其他技术栈里需要注意QT的事件循环不能被阻塞。比如用CLion写QT、用VS Code配置QT Designer本质都是调用命令行工具链。VS Code配置Qt Designer时经常出现“ui文件打开失败”或“designer启动不了”的问题。通常是Qt Tools插件的路径设置错误。打开用户设置找到Qt Tools Qt Executables添加你的QT安装路径并指定designer.exe所在目录。如果还是不行确认你装的QT版本是Desktop的版本别只装了嵌入式组件。CLion跑QT报“Error while building/deploying project”通常和编译套件有关。在CLion的Settings Build Toolchains里确认选择了正确的编译器然后CMake的Generator选对了。Windows下如果用的MinGW还要确认MinGW的路径里没有中文。这类IDE级配置错误看着吓人实际都是路径或编译器选择问题。7. 入门之后的路从“会跑demo”到“写出能用的软件”写到这里QT学习的第一阶段其实已经走完了环境能跑通窗口能弹出按钮能响应信号槽、多线程、打包发布这些高频痛点心里有数了。但要说真上手做项目还差一段距离。我个人的体会是入门QT最大的障碍不是语法而是思维模式的转变。C语言里你的程序是顺序执行的但在QT里main函数就是创建QApplication、进入事件循环然后……你的程序就不再按顺序跑了。所有逻辑都由信号驱动对象之间的关系由connect组织事件循环一旦关闭程序就退出。接受这个模型之后再看QT的任何功能都清晰很多。接下来比较值得花时间的几个方向也是“QT学习-2”里我会继续展开的内容第一是绘图。QPainter是自绘控件的核心热词里的“逻辑坐标系”“设备坐标系”就是从这里引入的。QPainter自带的坐标系变换能实现图形的平移、缩放、旋转做自定义进度条、曲线图、图表缩放全都靠它。第二是QChart与数据可视化。QChart封装了基于Qt Graphics View的图表绘制能画折线、柱状、饼图还支持缩放。热词里“qchart实现图片缩放”这类需求根本原理是对QChartView开启rubberBand加上对坐标轴的range调整。第三是更复杂的线程模型。QT的线程池、事件循环、定时器与线程的绑定关系值得反复研究。真正稳定的工控软件线程架构一定是很讲究的。最后再补充一点实际经验QT的学习资料非常多但也有很多过时内容。看到一篇博客先看它对应的QT大版本再决定要不要照抄。QT4的写法在QT5里多数还能运行但会有编译警告QT5的写法在QT6里已经有不少被改名或废弃。版本对齐是少走弯路的第一步。QT学习-1这篇就聊到这里环境装好了、机制理解了、坑踩少了剩下的就是多做几个小项目把知识变成肌肉记忆。下一期我准备重点拆解QPainter绘图和自定义控件的实现恰好能把热词里的坐标系统、绘图效率、自定义进度条这些点都串起来。
返回列表