ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Qt完整学习路线:从环境搭建到项目发布与崩溃排查

Qt完整学习路线:从环境搭建到项目发布与崩溃排查 我见过太多人学Qt的方式了装上Qt Creator拖几个控件写一个“Hello World”然后就卡住了。有C基础的人以为自己能直接起飞结果在信号槽和对象树这两个概念上栽了跟头完全小白呢更惨连MinGW和MSVC、Debug和Release都没搞明白就开始写代码最后连第一个窗口都运行不起来。今天这份路线图不是教你怎么拖按钮、怎么布局这种碎片化操作。我把它拆成一条完整的学习链路从版本选型、环境搭建开始到信号槽、对象树、事件循环这几个入门阶段必须啃下的硬骨头再往上走是QPainter绘图、多线程、消息队列、模型视图这些进阶分水岭然后是CMake工程化、VSCode配置、程序发布最后专门讲崩溃排查——毕竟Qt程序崩起来真想骂人。无论你是已经能把C语法背得滚瓜烂熟还是只学过几天C基础只要按这条路线走三个月后你至少能独立写完一个像样的桌面程序。1. 动手之前版本、安装和构建套件这步错了后面全错1.1 Qt 5还是Qt 6选错版本比选错编译器还难受每个加我微信问“Qt怎么学”的人我第一句话都是先别急着下载先选版本。当前环境下你必须面对的现实是存量项目里Qt 5仍然占大头尤其是5.15.2这个LTS版本大量工控、组态、桌面工具类软件还在用它。而Qt 6从6.2开始才真正适合生产环境6.5 LTS是目前更推荐的选择。我的建议很简单如果你是为了找工作、进企业做实际项目首选5.15.2如果是纯自己折腾、新项目没有历史包袱选6.5 LTS或更高版本。为什么这么分因为网上能找到的教程、博客、Stack Overflow答案至少七成以上是Qt 5时代的写法。你拿Qt 6去跑Qt 5的代码大概率会遇到模块拆分导致的变化比如Qt Charts从Qt 5的单独模块变成Qt 6的官方模块多媒体的API变化也不小。新手最怕的就是“照着教程敲代码结果编译不过”这一下就能劝退一半人。从Qt官网下载时你可能会发现在线安装器这个下载方式。这里有个很实用的技巧在线安装器对国内网络不太友好但你可以用国内镜像源加速。安装器启动后在设置里手动填入国内镜像地址下载速度能快几倍。这一步做完Qt的安装体验就从“让人绝望”变成了“可以接受”。1.2 编译器怎么选MinGW和MSVC的事一次说清很多人卡在“选择组件”这一步面对一堆勾选框不知道选什么。其实最核心的问题就一个你到底用MinGW还是MSVCMinGW是GCC在Windows上的移植版开源、免费、和Qt配合开箱即用调试器用GDB。它的最大优势是简单配好就能跑完全不需要额外装运行库。MSVC是微软的Visual C编译器和Windows生态的兼容性最好一些只有MSVC版本的第三方库你绕不开它。但用MSVC编译出来的程序发布给普通用户时目标机器上必须装了对应版本的Visual C Redistributable否则双击exe直接报错。对于刚开始学的朋友我强烈建议先用MinGW 64-bit。原因不是MinGW比MSVC好而是它让你把精力集中在“Qt本身”而不是“编译环境”上。等你真进了公司公司用哪个套件你就用哪个到时候再补MSVC的坑也来得及。这里再提一个新手最容易踩的坑项目路径千万不要有中文和空格。你在Windows上建了个文件夹叫“我的Qt项目”然后Qt Creator会告诉你构建失败错误信息长得像天书。把路径改成纯英文问题立刻消失。这问题我见过不下二十次。1.3 组件安装和第一个工程最容易翻车的三个位置Qt在线安装器里的组件非常多新手不用全装。一般建议勾选你选择的Qt版本下的MinGW或MSVC编译器对应你的选择、Qt Charts画图会用到热词里的qchart就是它、Qt Multimedia做音视频才需要先装了也行。创建第一个工程时有几个地方特别容易翻车套件选择如果你装了多个编译器创建工程时一定要确认当前选中了MinGW那套Kit否则你明明装了MinGW却还在用MSVC编译报错报得你怀疑人生。构建目录默认的构建目录在源码旁边构建产物和源码混在一起。建议单独指定一个build目录后续用命令行构建、看生成文件都会方便很多。Shadow build影子构建这其实是Qt Creator默认开启的它把编译产物放在单独的build目录里好处是源码目录干净缺点是你找不到exe在哪里。没关系构建完成后看“构建”输出窗口里的路径就行。安装完把启动页面上的几个示例工程跑起来重点看看每个示例是怎么组织的。看到能运行的那一刻你的Qt之路才算正式开始。开发快捷键这里提前说CtrlB构建、CtrlR运行、F5调试、CtrlI自动格式化这四个键从一开始就记住。2. 入门核心机制这5个东西不硬啃下来写再多代码都白搭2.1 信号槽Qt最伟大的设计也是新手第一座山很多人写了几年Qt对信号槽的理解还停留在“照着写connect”的层面。一旦遇到“为什么信号没触发”“为什么槽执行了两遍”“为什么跨线程就乱了”就抓瞎。所以我希望你在入门阶段就把信号槽吃透。用生活化的话说信号槽就是一个“广播-订阅”机制。某个按钮被点击了它就广播一声“我被点击了”谁对这个事件感兴趣谁就去订阅这个广播。发出信息的人不需要知道谁在听听的人也不需要知道广播从哪来。这就是信号槽和普通函数调用的本质区别解耦。Qt 5之后推荐的连接方式是函数指针语法connect(button, QPushButton::clicked, this, MainWindow::onButtonClicked);这种方式在编译期就检查信号和槽是否存在类型不匹配直接编译报错比老式的SIGNAL/SLOT宏安全得多。等你在Qt 5里看到宏写法能看懂就行了自己写的时候尽量用新语法。信号槽还有一个让新手困惑的地方它支持lambda表达式。我第一次看到connect(button, QPushButton::clicked, this, [](){ qDebug() clicked; });时也觉得很神奇。这里有个关键的坑lambda里如果捕获了this而对象的生命周期已经结束了再调用lambda就会访问已释放内存。所以如果你用lambda一定要确保发信号的对象和接收上下文活得足够久。2.2 对象树为什么new出来的QObject不会随便崩对象树是Qt的另一个核心设计也是唯一让我觉得“Qt确实和纯C不一样”的地方。Qt里几乎所有的类都继承自QObject而QObject支持父对象机制。当你new一个QWidget并传入parent时这个QWidget就被挂到了父对象的子对象列表里。父对象析构时会先析构所有子对象。这套机制解决了谁负责释放的问题。你在窗口上new了一堆按钮、标签、布局只要父窗口在堆上创建你几乎不需要手动delete它们。这也是为什么你能在代码里看到大量new却看不到对应delete的原因。但对象树也有自己的坑。最典型的**如果你在栈上创建了一个QWidget并给它指定了父对象程序结束时栈对象先析构父对象后析构父对象析构时会去释放一个已经无效的子对象指针直接崩溃。**示例void MainWindow::showDialog() { QDialog dlg(this); // 栈对象却指定了父对象 dlg.exec(); // 能弹出来 } // 函数结束dlg析构但父对象仍然持有一个悬空指针正确做法是QDialog *dlg new QDialog(this); dlg-exec();如果你想让一个对象稍后自动销毁可以用deleteLater()。它会等当前事件循环处理完再执行删除特别适合在槽函数里自己删自己的场景。2.3 事件循环QCoreApplication::exec()到底卡在哪了很多人在qq群问为什么我写了QCoreApplication::exec()之后的代码不执行是不是程序卡死了能问出这个问题说明还没理解事件循环。简单说exec()是一个无限循环它的工作是不断从事件队列里取出事件并分发处理。你的鼠标点击、键盘输入、窗口重绘、网络数据到达全都是事件全部排到这个队列里由事件循环一个个处理。exec()之后的代码当然不会执行因为它压根没退出它就在那里忙着处理事件。理解事件循环最大的价值在于它能解释为什么“界面卡死”这么常见。如果你在一个槽函数里写了一个死循环或者执行了一个耗时10秒的网络请求事件循环就被卡住了。在这10秒内鼠标点击、窗口刷新这些事件都得不到处理表现出来就是窗口无响应、转圈。所以从一开始就要养成习惯耗时操作绝对不要放在UI线程里做。等学到后面多线程那一节你就能真正解决这个问题。2.4 从布局到QFileDialog第一个像样的小工具入门阶段一定要亲手做一个小工具不是那种拖个按钮弹个窗的Demo而是真正能完成一件事的工具。我推荐做“文本文件行数统计器”因为它的功能链路恰好覆盖了Qt入门最经典的几个知识点。功能很简单点击“选择文件”按钮通过QFileDialog::getOpenFileName弹出文件选择对话框选中一个txt文件读取内容在界面上显示行数和字符数。void MainWindow::onSelectFileClicked() { QString filePath QFileDialog::getOpenFileName(this, 选择文件, , 文本文件 (*.txt)); if (filePath.isEmpty()) { return; // 用户取消了选择 } QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; } QTextStream in(file); QString content in.readAll(); file.close(); int lineCount content.count(\n) 1; ui-labelResult-setText(QString(行数%1).arg(lineCount)); }这个练习能让你把信号槽、布局管理、QFileDialog、文件读写、字符串处理全部串一遍。做完之后你会对“一个完整的Qt程序是怎么跑起来的”有直观的感知。布局管理这里多说一句不要用绝对坐标拖控件。新手总喜欢把按钮拖到“看起来好看”的位置一旦窗口大小变化所有控件位置全部错乱。正确做法是用QVBoxLayout、QHBoxLayout、QGridLayout组合布局让控件随着窗口自适应。2.5 顺手把C短板补上给完全小白的特别章节如果你是完全小白前面看下来可能已经有点晕。没关系这是正常的——Qt是C的框架你写Qt代码本质上是在写C。所以我建议完全小白的路线是先花两周过一遍C基础再回来学Qt。具体补什么类的定义和封装、继承与多态、指针与引用、const关键字、STL容器vector、string、map、lambda表达式。这些在Qt里天天用到。尤其是lambda信号槽里处处是它不掌握寸步难行。有C基础的朋友可能会问那我能不能直接跳过C可以但建议你把一个东西复习一下指针和内存生命周期。Qt虽然帮你管理了很多对象的内存但当你自己new一个缓冲区、或者和一个C语言接口打交道时指针问题立刻浮现。3. 进阶分水岭从“会写控件”到“能设计程序”3.1 QPainter绘图Qt做组态和画板的核心当你能熟练使用各种控件、信号槽、布局之后就该接触Qt最强大也最让人上瘾的部分了——QPainter绘图。热词里的“qt桌面画线”“qt做组态”本质都是QPainter在发挥作用。我最初做工业组态软件时最大的感慨是Qt的绘图机制简直是为此量身定做的。你用QPainter在paintEvent里画矩形、画线、画文字、画图片一切的基础都是三大步骤void MyWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setPen(QPen(Qt::blue, 2)); painter.setBrush(QBrush(Qt::yellow)); painter.drawRect(50, 50, 200, 100); painter.drawLine(QPointF(0, 0), QPointF(300, 300)); }这个机制最关键的一点是所有绘制都必须在paintEvent里进行。你不能在鼠标事件里直接“画一条线到屏幕上”因为窗口一旦被遮挡、最小化、刷新你画的东西就会被抹掉。正确做法是在鼠标事件里保存数据然后调用update()请求重绘系统会在合适时机调用paintEvent你在那里根据保存的数据绘制。做组态软件时这个模式就是全部基础。你拖拽一个矩形到画布上鼠标事件里记录矩形的坐标松开鼠标时更新数据并触发重绘paintEvent里把当前所有图元全部画出来。就是这样一个看似简单的循环构成了工业组态软件的骨架。3.2 模型视图架构别再一个MainWindow里写三千行入门的项目往往很随意所有逻辑全塞在MainWindow里。等你要做表格、做列表、做一个要显示大量实时数据的曲线图工具时这种写法会把你拖垮。Qt的Model/View架构简单说就是把数据和显示分开。QTableView、QListView这些是View只管怎么展示数据存在Model里常见的有QStandardItemModel更高级的可以继承QAbstractTableModel自己实现。以前做实时曲线时我用QChart配合自定义Model效果非常理想。QChart是Qt Charts模块的图表控件能画折线图、柱状图、饼图。实时曲线场景下最忌讳在UI线程里频繁刷新全部数据。我的做法是子线程把数据放到一个队列里主线程定时器每隔100毫秒从队列取一批数据追加到QChart的series里。// 追加一个数据点 series-append(timestamp, value); // 别忘了更新坐标轴范围不然曲线看不到 chart-axisX()-setMin(timestamp - 60); chart-axisX()-setMax(timestamp);热词里提到“qchart实现图片缩放qt”——图片缩放是QPixmap::scaled而图表缩放通常是坐标轴范围的变化或者QChartView的setRubberBand(QChartView::RectangleRubberBand)拖拽鼠标就能框选放大。这个小功能在数据监控软件里特别实用。3.3 多线程和消息队列界面不卡是底线Qt程序最容易出现的生产事故就是界面无响应。只要你的程序里有耗时操作比如处理大文件、网络请求、复杂计算放到UI线程里跑界面必卡。这个问题的标准解法是多线程。你可能会想到直接继承QThread重写run()。能用但不推荐。我更推荐的做法是创建一个QObject子类的Worker用moveToThread把它移动到子线程里通过信号槽和主线程通信。class Worker : public QObject { Q_OBJECT public slots: void doWork() { for (int i 0; i 100; i) { // 处理数据... emit progress(i 1); QThread::msleep(50); } emit finished(); } signals: void progress(int percent); void finished(); }; // 在主线程里 QThread *thread new QThread(this); Worker *worker new Worker; worker-moveToThread(thread); connect(thread, QThread::started, worker, Worker::doWork); connect(worker, Worker::progress, ui-progressBar, QProgressBar::setValue);这里的核心原理就是Qt的信号槽机制在跨线程时自动变成了队列连接。信号发出后不会立即调用槽函数而是被包装成一个事件投递到接收者所在线程的事件循环里等那个线程的事件循环来处理。这本质上就是一个消息队列——热词里的“qt中的消息队列”讲的就是这个机制。多线程最常踩的坑是在子线程里直接操作UI控件。Qt的UI控件不是线程安全的你从子线程里调用label-setText()程序可能会崩溃或行为异常。记住一个铁律子线程不能直接碰UI只能通过信号把数据传回主线程在主线程里更新UI。这个习惯越早养成越好。如果只需要做并行计算Qt还提供了QtConcurrent模块比如QtConcurrent::run()把函数丢到线程池里跑比手动管理QThread简单得多。但线程通信这件事还是要靠信号槽。3.4 从QSS到自定义控件让程序看起来不像教学Demo我见过太多Qt程序功能没问题但界面停留在“Windows 98风格”一打开就透着一股教学气息。想让程序看起来专业QSSQt样式表是你必须掌握的技能。QSS的语法和CSS非常像基本上一学就会QPushButton { background-color: #4A90D9; color: white; border-radius: 6px; padding: 6px 16px; } QPushButton:hover { background-color: #357ABD; }你可以把QSS写在一个.qss文件里程序启动时加载QFile qss(:/style.qss); qss.open(QFile::ReadOnly); app.setStyleSheet(qss.readAll());做组态软件时QSS配合QGraphicsView这套框架非常好用。你可以用QGraphicsItem做图元用属性存样式运行时用setStyle改变图元的颜色、闪烁状态。热词里的“qt做组态”大部分场景都可以用QGraphicsViewQGraphicsItemQSS渲染来解决。当你发现QSS控制不了某些特效时就需要自己继承QWidget重写paintEvent做自定义控件了。比如仪表盘、进度圆环、带拖拽手柄的滑块这些用纯QSS很难做到但用QPainter写起来却很简单。自定义控件的另一大好处是封装成独立的类可以复用这也是一种架构能力的锻炼。4. 离开Creator也能干活工程化与构建发布实战4.1 qmake还是CMake这个选择影响你后面所有工作流Qt Creator默认用的是qmake它的工程文件是.pro。qmake非常简单几行配置就能构建一个项目。对于学习阶段和内部小工具qmake完全够用。但当你开始接触真正的开源项目、大型软件、需要跨平台CI构建时CMake才是事实标准。Qt 6里CMake已经成为默认构建系统。我的建议很直接入门阶段用qmake但不要排斥CMake。第二阶段开始迁移到CMake的写法。因为招聘市场上要求“熟练使用CMake”的岗位比比皆是而qmake几乎没有单独被列为要求。一个最基本的CMake工程文件长这样cmake_minimum_required(VERSION 3.16) project(MyApp VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS Widgets Charts REQUIRED) add_executable(myapp main.cpp MainWindow.cpp) target_link_libraries(myapp Qt5::Widgets Qt5::Charts)在命令行构建时cmake -S . -B build -DCMAKE_PREFIX_PATHC:/Qt/5.15.2/mingw81_64 cmake --build build -j8CMAKE_PREFIX_PATH指向Qt的安装目录这个参数CMake新手经常忘记导致find_package找不到Qt编译报错。如果你用Qt Creator的CMake套件它会自动帮你设置但到了VSCode和命令行环境这一步必须手动处理。4.2 VSCode配Qt轻量开发环境的配置笔记热词里“vscode配置c/c环境”和“vscode配置qt designer”出现频率很高说明很多人在尝试用VSCode开发Qt。这条路走得通但比Qt Creator曲折。要用VSCode写Qt你需要装这几个扩展C/C、CMake、CMake Tools。关键在于配置文件c_cpp_properties.json决定IntelliSense能不能正确识别Qt头文件{ configurations: [ { name: Qt, includePath: [ ${workspaceFolder}/**, C:/Qt/5.15.2/mingw81_64/include/** ], defines: [], compilerPath: C:/Qt/5.15.2/mingw81_64/bin/g.exe, cStandard: c17, cppStandard: cpp17 } ], version: 4 }tasks.json负责构建launch.json负责调试。调试时需要配合GDB指定miDebuggerPath为Qt安装目录下的gdb.exe。这里有个很常见的坑Qt生成的预处理文件moc、uic、rcc必须由CMake或qmake在构建时自动处理。VSCode本身不会帮你生成这些所以你不能像写纯C那样直接编译。这也就是为什么我建议你第二阶段的CMake功底要打好——VSCodeCMake的配合比VSCodeqmake要顺畅得多。4.3 发布与部署把程序发给别人时别再让他装一堆东西程序写完了发给朋友用他双击exe提示“找不到Qt5Core.dll”或者“无法定位程序输入点”——这个场景新手一定经历过。这涉及Qt程序的发布流程。最基本的发布方式是在Qt Creator里用Release模式构建然后找到编译产物执行windeployqt myapp.exewindeployqt是Qt自带的部署工具它会自动把exe依赖的Qt DLL、插件、QML文件、翻译文件全部复制到exe所在目录。运行完这个命令把整个目录打包发给别人就能运行。如果你用的是MSVC编译器发布时还要注意目标机器上有没有对应的Visual C运行库。这就是为什么很多人安装软件时会看到“需要安装vcredist”的提示。你可以把vc_redist.x64.exe一起打包或者要求用户先安装。发布还有一个高频坑程序在自己电脑上正常在别人电脑上报“此应用程序无法启动因为无法找到Qt platform plugin windows”。这个错误几乎都是因为缺少platforms/qwindows.dll插件或者插件版本和主程序不匹配。windeployqt正常会复制这个插件但如果你手动拷贝过Qt的DLL很可能把不同目录下的同名DLL搞混了。记住Qt的DLL分布在多个子目录windeployqt是按依赖关系自动复制的手动拷贝极易漏掉插件目录。4.4 国内镜像源和开发效率习惯热词里高频出现的“qt下载”“qt下载官网”“linux qt 国内源”本质都是Qt安装和更新源的问题。Qt在线安装器支持自定义仓库地址国内可以用清华、中科大的镜像。设置方法启动安装器后在设置里添加https://mirrors.tuna.tsinghua.edu.cn/qt/镜像路径。如果这个配置不会弄也别慌还有一个开箱即用的方案直接在镜像站点下载离线安装包。离线包虽然大但一劳永逸安装时不需要网络特别适合网络环境不好的情况。另外建议你从一开始就使用git管理代码。哪怕只是自己一个人写也要保持“每个功能点一个commit”的习惯。Qt Creator内置了git支持操作非常方便。这个习惯等你进团队协作时会帮你省掉大量沟通成本。5. 崩溃排查与调试Qt程序上线前必须掌握的保命技能5.1 崩溃了先别急着怀疑Qt本身很多新手第一次遇到Qt程序崩溃第一反应是“Qt这框架是不是有bug”。实际上90%以上的崩溃原因都在自己代码里。最常见的几种空指针解引用。槽函数里对某个对象调用了方法但这个对象是nullptr。悬空指针。对象已经被delete了但代码还在访问它。用对象树时特别容易出这种问题。跨线程访问UI。子线程里操作控件轻则警告重则崩溃。栈上对象配合对象树。前面讲过栈对象析构后父对象还持有指针。排查时先打开Qt Creator的调试模式编译Debug版本在崩溃处程序会停下来。看调用堆栈是最重要的操作崩溃位置通常在堆栈最上方几层。如果堆栈显示在Qt内部代码里就往上看你的代码在哪一层调用了Qt。5.2 借助Breakpad捕获崩溃现场热词里出现了“qt中使用breakpad”这是个很有价值的话题。你的程序发布出去之后用户那边的崩溃你看不到、摸不着这时候就需要一个崩溃捕获机制让程序在崩溃前留下现场。Google Breakpad是一个跨平台的崩溃上报库它会在程序崩溃时生成一个dump文件里面记录了崩溃时的堆栈、线程、寄存器等信息。Qt项目里集成Breakpad并不复杂社区还有封装好的QBreakpad类把初始化封装得很简单#include qbreakpad.h int main(int argc, char *argv[]) { QApplication app(argc, argv); QBreakpadInstance.setDumpPath(crashes/); // ... 正常启动界面 return app.exec(); }配置好以后程序在任何地方崩溃都会在crashes目录下生成一个.dmp文件。你把这个文件收集回来用cdb或者Breakpad的minidump_stackwalk工具配合编译时生成的pdb符号文件就能还原出崩溃的调用堆栈。这里有个提前要做的事发布release版本时一定要同时保留符号文件pdb或sym。没有符号文件dump文件只能告诉你一个地址你根本不知道对应的是哪一行代码。项目管理上每次发版都应该把符号文件归档保存。5.3 内存问题排查对象树不是万能保险Qt的对象树能帮你管理大部分子对象但它不负责new出来的普通C对象也不负责你显式delete之后还残留的指针。排查内存问题时我推荐两个工具VLDVisual Leak DetectorWindows下和MSVC配合效果很好程序退出时会在输出窗口打印没有释放的内存分配位置。AddressSanitizerASANMSVC和MinGW都支持编译时加上-fsanitizeaddress运行时如果发生内存越界、使用已释放内存它会直接打出一个详细的报告。Qt自己的QObject::deleteLater()也是一个经常踩坑的地方。deleteLater()的意思是“等当前事件循环处理完再删除”如果你在主线程处理某个事件时对一个对象多次调用deleteLater()虽然不会重复释放但你在它“later”删除之后又给这个对象发信号就可能访问到悬空指针。另外qcoreapplication::exec() 之后就无法捕获了这个现象我解释一下在exec()开始运行后主线程才真正进入事件循环。如果你的崩溃发生在exec()之前比如某些全局对象构造期间那Breakpad的捕获机制可能还没就绪dump文件就不完整。所以Breakpad的初始化要尽可能早放在程序加载后的第一位置避免“崩溃发生在捕获机制之前”。6. 三个月路线图从今天安装到做出完整项目6.1 分阶段计划别贪多求快最后给你一条可执行的时间线。这是基于我见过大量学员、确认有效的一条路线第1-2周完成环境安装、跑通第一个工程、掌握信号槽的三种写法、完成“文本文件行数统计器”小工具。每天保证2到3小时不要写大项目只写10分钟就能完成的小Demo。第3-6周对象树、事件循环吃透。用QPainter做一个简易画板支持鼠标画线、笔迹保存用QChart做一条可以实时滚动的曲线。这个阶段你会开始感受到“卡顿”问题——恭喜你该学多线程了。第7-10周Qt多线程和消息队列实践。做一个批量文件处理的工具界面上有进度条过程中不卡。同时把工程从qmake迁移到CMake练习在VSCode和命令行下构建。第11-12周做一个完整项目比如“截图工具”、“桌面便签”、“文件批量重命名工具”要有完整的界面、配置持久化、异常处理最后发布成独立exe给别人正常使用。6.2 每个阶段练手项目怎么选练手项目比看教程重要十倍。下面是几个比较好的项目任务待办事项Todo List覆盖布局、增删改查、QListWidget、数据持久化到本地JSON。麻雀虽小五脏俱全。简易画板覆盖鼠标事件、QPainter绘图、保存为图片。热词里的“qt桌面画线”就是这个方向。实时曲线图覆盖QChart、定时器、多线程取数、坐标轴缩放。做出来就有工业软件的内味了。组态小工具在QGraphicsView上拖拽矩形、圆形、连线图元能保存和加载布局。难度最高但做完这个你已经有能力去做真正的工业组态软件了。6.3 避坑心得按我个人的经验这个过程中你一定会遇到的问题提前预警一下视频看十遍不如自己敲一遍。Qt的坑都是“上手才知道”的看别人视频里敲代码很顺自己一跑全是问题。所以每看完一节教程当天就必须复现一个对应功能。报错信息要认真读。Qt的编译报错确实长但关键信息往往在前面几行。把第一行报错复制到搜索引擎里基本都是正确答案。先看文档再搜答案。Qt官方文档写得其实非常清晰很多界面控件的用法、参数含义、示例代码都有。你遇到的问题九成在文档里能直接查到。一个项目反复重构。不要写完一个项目就扔了。等你学到多线程和模型视图之后回头把你第一周的“文本文件行数统计器”重构一遍。你会发现当初的代码很笨而这个“觉得当初笨”的过程就是你在进步的证据。Qt学习路上没有捷径但有一条能少掉很多坑的路先啃机制再写项目先学构建再看教程报错先能发布再谈优化。按这条路线走下去三个月后你回头看会感谢今天那个愿意慢慢打基础的自己。
返回列表