基于Qt和C++实现旅行模拟查询系统:从架构到发布完整指南 基于QT(C)实现图形界面旅行模拟查询系统做过C课设的朋友应该都有体会题目拿到手往往就是一句“基于QT(C)实现图形界面旅行模拟查询系统”看似清清楚楚真开始动笔却发现到处是坑。光是把Qt装好、跑通一个空白窗口对新手来说就已经能劝退一大半人了更别提后面还要做数据存储、路线模拟、查询界面这些内容。这里我先把这个项目说透它本质上是一个“数据管理 业务逻辑 图形交互”三合一的桌面应用。底层是C的容器、类、文件读写和算法逻辑上层是靠Qt框架撑起来的窗口、控件、事件响应和绘图。项目不只是练GUI还练你怎么把一个完整的小系统拆开设计再组装起来。适合正在学C想找项目练手的人、被课设折磨的学生、以及刚接触Qt想快速上手桌面开发的初学者。我当时做这个题目的思路很简单界面清爽、交互合理、模拟过程能直观看出来而不是一堆干巴巴的文字输出。这篇文章就把我完整的实现过程、设计决策和踩过的坑都放出来照着走这个系统你可以稳稳做出来。1. 需求拆解与总体设计思路1.1 标题背后到底在要求什么“旅行模拟查询系统”这个词组可以拆成两部分理解。“查询系统”是核心业务。你要能给用户提供线路查询、车次查询、票价查询这些功能。做个比喻就是以前火车站人工窗口的“请问到XX市怎么走”系统得能回答有哪几班车、什么时间发车、多少钱、要坐多久。“旅行模拟”则是把查询结果变成动态过程。用户选好一条路线之后系统能够模拟“从出发站上车、途经若干站、最终到达终点站”的完整过程并且这个过程要在界面上动态展示出来——车到哪一站了、下一站是什么、运行了多长距离。这部分是区分“及格作品”和“优秀作品”的关键。数据形态上你得有一份基础数据比如若干城市、城市之间的线路、各线路的站点和票价。这些数据可以内置在代码里也可以放在外部文件里加载。工程化的做法是后者用文本文件存基础数据程序启动时一次性读入内存这样改数据不用重新编译。1.2 技术选型为什么是Qt而不是其他方案很多人在想做个图形界面为什么不选Python的Tkinter或者PyQt我的选择是纯C 原生Qt Widgets理由很实在。第一题目里写了C那技术栈就锁死了。用Python调PyQt虽然快但本质上绕过了C的核心练习答辩时会被问到“你C体现在哪”这种尴尬问题。第二Qt是C图形界面领域事实上的标准。它不只是一个控件库还提供了完整的事件循环、信号槽通信机制、绘图引擎QPainter、以及庞大的工具类库QString、QVector、QFile、QTimer这些能让你的C代码写起来舒服得多。简单说Qt替你搞定了窗口系统底层的脏活你只需要关注业务本身。第三可发布性。Qt程序配合windeployqt工具可以打包成独立的exe发给评委就能跑不需要装Python环境。这一点在答辩现场非常重要——你不想在演示的时候因为环境不对而社死。对比一下其他方案MFC太老且界面丑陋wxWidgets资料少直接Win32 API纯属折磨自己。Qt是目前唯一同时满足“专业、跨平台、资料多、学习曲线可接受”的选项。1.3 系统架构与模块划分动手写代码前先把系统的模块边界画清楚。我当时的做法是分四块数据层Data负责城市信息、线路信息、车次信息的定义和加载。定义对应的结构体或类提供统一的读取接口。业务逻辑层Core路线查询、换乘计算、费用计算、模拟行程的推进逻辑。不涉及任何界面元素方便单独测试。界面层GUI主窗口、查询面板、结果列表、模拟展示区域的布局和控件管理以及用户事件的响应。公共工具模块时间格式化、随机数封装、字符串处理等小工具的集合。这种分层的好处是逻辑和界面不纠缠在一起改界面不会影响算法调算法不会把界面搞崩。哪怕是一个课设级别的项目采用这种结构写出来的代码无论是可读性还是后续扩展性都会比单文件堆代码高出几个档次。能力允许的话后续把数据层换成SQLite数据库也只需要改动数据层一个地方。2. 环境搭建与工程创建2.1 版本选择Qt 5.15.2为何是稳妥选择我选的是Qt 5.15.2。这个版本是Qt 5系列的最后一个长期支持版本稳定、资料多、踩坑解决方案在网上随手一搜就有而且兼容性非常好。Qt 6虽然在架构上更新但许多老教程和第三方模块还停留在Qt 5对一个新手项目来说没必要冒这个风险。安装时注意Qt安装包体积很大动辄几个GB下载慢很正常。选择组件的时候只需要勾选你需要的部分Qt 5.15.2下的MinGW 8.1.0 64-bit或MSVC 2019 64-bit根据后面说的工具链来定Qt CreatorIDE必须Qt Designer一般随Creator一起带上了界面拖拽设计要用没必要把所有组件都装上又占硬盘又费时间。2.2 编译器工具链MinGW还是MSVC这是新手最容易迷糊的地方。Qt本身是跨平台的但你在Windows上开发需要选一个底层的编译器。两个选项MinGWGCC的Windows移植版开源、免费、安装简单、和Qt搭配不需要额外的Visual Studio。对新手最友好的方案。MSVC微软的编译器需要装Visual Studio体积很大但生成的程序性能略好且能配合一些Windows专用工具。我的建议是新手无脑选MinGW。理由很简单——安装快、环境配置少、中文资料多。等到以后要做大型商业项目再考虑MSVC也不迟。而且要注意Qt版本、编译器版本、以及你下载的套件三者必须匹配混搭就会出现那个经典报错cannot mix incompatible Qt library (version ex50601) with this library。这是版本不匹配引起的后面排查部分会细说。2.3 创建Qt Widgets Application工程打开Qt Creator选择“New Project”然后按以下流程操作选择Application → Qt Widgets Application。填项目名称比如TravelSimulationSystem路径不要带中文和空格。构建套件选你刚安装的MinGW或MSVC 64-bit套件。类信息里基类选择QMainWindow类名默认MainWindow。一路下一步完成创建。创建完你会得到一个最基本的窗口程序里面有菜单栏、工具栏、状态栏的骨架。按一下左下角的绿色三角运行如果看到一个空窗口弹出来说明整个环境链路已经通了。这是第一个里程碑。2.4 界面设计Qt Designer拖拽还是代码手写Qt提供了两种界面构建方式一种是Qt Designer可视化拖拽另一种是手写代码布局。我两个都试过最终实际项目中大部分是手写代码布局。但这两个方式不是替代关系而是配合关系。先说Qt Designer。它的优势是拖拽控件非常直观所见即所得非常适合快速搭出界面原型。比如你要放一排按钮、一个表格、一个标签拖几下就出来了生成的.ui文件可以用ui_MainWindow.h头文件方式集成到项目里必要的控件还能通过findChild或者已生成的成员变量直接访问。但它的劣势也明显复杂的动态布局比如运行时根据数据量生成多个卡片用Designer反而难做而且一旦.ui文件被改坏排查起来比较痛苦。理解底层原理后你就会明白Designer生成的无非就是控件的位置和属性设置代码既然是代码那手写也没什么神秘的。我的建议是先用Designer搭大结构再用代码做动态部分。比如主窗口的布局骨架用Designer拖出来后续动态添加的行程节点卡片、模拟进度条、路线标签这些全部手写代码。这里我不展开代码细节但要强调一个设计习惯主窗口类里不要把所有控件都堆成成员变量而是用一个专门的QWidget作为“内容容器”你在里面new各种子控件。这样切换页面、替换内容时特别方便。3. 核心功能模块设计与实操3.1 业务数据结构建模做这种系统最怕的是数据结构没想清楚就开写代码。我当时把数据结构分成了两层。第一层是基本实体// 城市 struct City { QString name; QString code; QPointF pos; // 用于在界面上绘制示意位置的坐标 }; // 车站 struct Station { QString name; QString cityCode; bool isTransfer; // 是否换乘站 }; // 线路 struct Route { QString id; QString startCity; QString endCity; QVectorQString stationList; double distance; // 总里程 double basePrice; // 基础票价 };第二层是运行计划也就是每天有哪些车次在跑// 车次 struct Train { QString id; // 如 G1234 QString routeId; QTime departTime; QTime arriveTime; double price; int remainSeats; };用这些结构体组合起来一个简单的铁路网模型就有了。你不需要做到真实铁路那么复杂但结构必须要能回答查询的问题某城市到某城市有没有车票价多少中间停哪些站这里有个关键建议所有数据都通过一个DataManager类来加载和管理界面层绝不直接操作原始容器。DataManager内部可以用QHashQString, Route这种结构做索引也可以维护一个QVectorRoute做顺序遍历。另外数据加载建议放在构造函数中给一个默认数据集的兜底防止文件缺失时程序闪退。3.2 随机数的正确玩法“旅行模拟”里少不了随机元素随机生成一条推荐旅程、随机分配一个座位、模拟时随机出现一些波动。C里常用的随机数获取方式有好几种选错了会出问题。C语言时代的std::rand()权当不存在它的应用最多是随机一个整数但质量差、范围不好控制、分布不均匀。现代C建议用random库#include random std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distributionint dist(0, cityList.size() - 1); int idx dist(gen);Qt也提供了qrand()和qsrand()本质上是对rand()的包装简单场景也能用但既然用C11及以上那就直接用mt19937。注意random_device在不同编译器上实现不同有的MinGW版本它返回的不是真正的硬件熵表现是“每次运行随机结果都一样”这时候可以改用std::chrono时间戳做种子unsigned seed std::chrono::system_clock::now().time_since_epoch().count(); std::mt19937 gen(seed);随机数在系统里的一个典型用途当用户没指定具体目的地时系统“随机推荐一条旅行路线”给用户。这种功能看起来很小但在演示时非常抓眼球能在答辩时加分。3.3 路线查询算法“直达”和“中转”的两种策略查询是整个系统的“面子工程”功能上最少要做两层。直达查询起点和终点在同一条线路上返回直接车次。实现方式很简单遍历所有车次检查起点站和终点站是否都在该车次的站表里并且起点站在终点站之前。如果有多辆车可选按出发时间排序。中转查询起点到终点没有直通车时找一个中转站。逻辑可以粗暴但有效遍历所有站点找出既能从起点到达、又能到达终点的站点作为中转站。实现上就是两次“可达性判断”。更精细的做法是维护一个邻接表跑BFS或Dijkstra。实际写的时候 Dijkstra 最简版本并不难所有站点作为节点每条线路的相邻站之间建一条带权边权重用里程或时间。跑一遍最短路算法就能得到最优换乘方案。这也是真正体现C算法功底的地方。查询结果统一封装成一个结构struct QueryResult { bool success; QVectorTrain directTrains; QVectorTransferPlan transferPlans; QString message; };界面层拿到这个结果后展示在列表和表格里就行。3.4 模拟引擎让旅途“动”起来模拟部分是这个系统的亮点。我实现的方式很简单用QTimer驱动一个状态机。先定义一个枚举表示行程状态enum class TripState { Waiting, // 等待出发 Running, // 运行中 Arrived, // 已到站 Finished // 全部完成 };每次用户点“开始模拟”就把选中的车次信息和路线塞进一个TripSimulator类这个类内部有一个currentStationIndex变量指向当前所在站点。流程是这样的设置currentStationIndex 0对应起点站状态为Waiting。启动QTimer每隔500毫秒触发一次onTick。每次onTick里判断如果是Waiting那么1秒后自动发车状态变为Running如果是Running站点索引加1更新界面上的站点标签、进度条如果索引到达终点状态变Finished停止定时器。实现时核心代码就几行但界面上的视觉反馈非常丰富。我做了三块展示区顶部一个大的路线示意条从左到右排布所有站点的名称当前站高亮中间是一张“示意地图”用QPainter画几个圆点表示城市线路连接线表示路线列车位置用一个小图标沿着路径移动底部是信息面板实时文本记录“列车已从XX出发正前往XX”。第三块其实是最容易吸引眼球的——用QPainter坐标换算把列车的位置按当前站点在总线路中的比例线性插值到两个城市坐标之间。只要公式对了视觉上就是一辆车在地图上“跑”起来特别直观。关于QPainter坐标换算的一点关键提示实际地图坐标需要经过一个“世界坐标到视图坐标”的变换建议用统一的缩放函数处理别在绘图事件里手写一堆魔法数字。除了列车的位置我还模拟了速度波动每次tick里用随机数在基础速度上加减一个百分比让到达时间不完全固定。这个细节能让演示效果显得更真实。3.5 数据持久化文本文件读写一个完整的系统不能每次手动改代码里的数据。我把城市、线路、车次数据放在一个data.txt文件里程序启动时加载。格式很简单每个字段用逗号分隔CITY,北京,100,50 CITY,上海,400,300 ROUTE,R001,北京,上海,北京,天津,济南,南京,上海,1200,550 TRAIN,G101,R001,08:00,13:30,550,200解析用QFile配合QTextStream读取split(,)之后逐字段处理。统一封装到DataManager::loadData()里。这里有一个重要的工程细节数据文件和可执行文件的位置关系。如果你用QFile(data.txt)这种相对路径程序的工作目录不同会导致文件找不到。稳一点的做法是QString path QCoreApplication::applicationDirPath() /data.txt;这样不管你从哪个路径启动程序都能正确找到数据文件。发布的时候把data.txt和exe放在一起就行。4. 界面开发与交互实现4.1 主界面布局规划主界面我采用了经典的三栏结构左侧是控制面板出发城市、目的城市、出发日期、查询按钮、随机推荐按钮。中间是结果区域用QSplitter分隔上下两部分上半部分放QTableView显示车次列表下半部分放QTextBrowser显示详细的换乘方案。右侧是模拟展示区域一个自定义绘制的QWidget用来显示地图和列车运行轨迹。// 简化示意 auto *mainSplitter new QSplitter(Qt::Horizontal, this); mainSplitter-addWidget(createControlPanel()); mainSplitter-addWidget(createResultPanel()); mainSplitter-addWidget(createSimulationPanel()); setCentralWidget(mainSplitter);布局做完之后重点就是事件关联了。Qt的“信号槽”机制是核心比如点击查询按钮后触发查询逻辑connect(queryButton, QPushButton::clicked, this, MainWindow::onQueryClicked);信号槽有一点需要特别说明信号和槽的参数列表必须匹配否则无法连接。这在编译期不会报错但运行时可能出现“无法连接到槽”的警告。一定要在帮助文档里查一下connect的几种重载形式用新语法函数指针而不是旧的宏方式因为新语法能在编译期检查错误而旧语法一旦参数写错等运行时才会发现。4.2 数据展示QTableWidget还是QTableView显示查询出的车次列表很多新手会直接用QTableWidget因为它简单。但我建议用QTableView QStandardItemModel。QTableWidget其实内部也维护了一个model但它把view和model合在一起灵活性差。用 QTableView Model 的方式你可以单独控制某列的排序轻易给整行加背景色比如推荐行程用黄色高亮将来想换成数据库表直接换model就行。QStandardItemModel *model new QStandardItemModel(this); model-setHorizontalHeaderLabels({车次, 出发, 到达, 历时, 票价, 余票}); QStandardItem *item new QStandardItem(train.id); model-appendRow({item, new QStandardItem(...)}); ui-tableView-setModel(model);注意QStandardItemModel不是线程安全的在工作线程里更新数据不能直接操作model要用信号把数据传回主线程再更新界面。对本项目来说查询逻辑放主线程就够快了不必引入多线程除非查的数据量真的很大。4.3 信号槽机制的进阶用法如果只是按钮点击、列表选择信号槽的基础用法已经够了。但有一个进阶场景值得好好了解传递自定义类型。比如你要把一个Train对象通知到模拟器模块不能直接connect因为Qt默认只识别自带类型。解决办法是用Q_DECLARE_METATYPE宏声明你的自定义类型然后注册Q_DECLARE_METATYPE(Train) qRegisterMetaTypeTrain(Train);如果不注册编译时connect新语法可能还能过但运行时执行队列连接时会出现Cannot queue arguments of type Train的错误。我实际踩过的另一个坑把耗时逻辑放在槽函数里直接执行界面会卡住。比如在点击查询的槽里做全网络节点的Dijkstra数据量小还好万一数据规模稍大界面会明显卡顿。解决方案是加一个QElapsedTimer测时间如果超过几百毫秒就用QtConcurrent::run放到后台线程再用信号把结果传回UI线程。4.4 可视化地图与QPainter绘图到了模拟展示区QPainter就派上用场了。这是一个自定义控件的paintEvent实现。绘制顺序很关键我的顺序是填充背景浅灰色渐变模拟纸质地图的质感绘制城市节点圆形城市名绘制线路线段/贝塞尔曲线连接城市绘制当前列车位置一个小箭头图标沿路径方向旋转角度绘制站点被选中的高亮效果。void SimMapWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 1. 背景 // 2. 城市节点 // 3. 线路 // 4. 列车位置 }绘制列车位置时利用当前站点和下一站点的坐标做一个线性插值按当前进度比例算出位置QPointF pos startPos (endPos - startPos) * progress;这里progress取值范围0到1由定时器每次tick累加一个固定步长来控制。列车方向角可以用std::atan2算出两点连线与水平轴的夹角然后旋转画笔绘制一个三角形或小车形状。需要特别提醒的是paintEvent里不要做耗时操作不能读文件、不能new大对象。因为窗口每次刷新都会调用它做耗时会直接拖垮整个界面响应。我当时就吃过这个亏画节点时用了一个复杂的模糊滤镜结果窗口拖起来像PPT翻页后来全部改成了预渲染的QPixmap缓存性能一下就上来了。4.5 动态添加行程卡片模拟面板上除了地图我还设计了一排“行程卡片”——每个卡片显示一站的信息站点名称、到达时间、里程、天气随机生成的。这些卡片不是写死在.ui里的而是在运行时根据线路站点数量动态生成的。for (int i 0; i stationList.size(); i) { auto *card new TripCardWidget(stationList[i], i 1, this); tripLayout-addWidget(card); }用QVBoxLayout动态addWidget即可。每次模拟开始前先clearLayout清空旧卡片再生成新卡片。这里最大的坑是清空Layout要用while(layout-count())循环取itemdelete掉对应的widget而不是直接layout-clear()否则会出现控件残留或内存泄漏。5. 完整运行效果与发布打包5.1 联调把模块拼起来当所有模块独立完成之后联调是问题高发期。我最常遇到的麻烦是查询结果传给模拟器的信号没接上、绘制地图的坐标没正确初始化导致列车跑到画面外。这里建议的联调顺序是先调数据加载确认读写没有问题再调查询逻辑用控制台qDebug()输出结果验证然后接界面查询按钮看表格是否正常显示最后接模拟器看定时器与地图动画是否流畅。千万别一上来就打开全部功能调试问题会叠在一起无法定位。一次只调通一条路径这是我做所有软件的通用原则。5.2 打包发布windeployqt的正确用法Qt程序不能直接把exe拷给朋友用因为缺少一堆DLL。这时候需要windeployqt工具来自动拷贝依赖库。大致步骤用Release模式编译你的项目得到TravelSimulation.exe注意一定是Release不是Debug。打开Qt自带的命令行工具如“Qt 5.15.2 (MinGW 8.1.0 64-bit)”切到exe所在目录。执行windeployqt TravelSimulation.exe工具会自动把需要的Qt DLL和插件拷贝到exe同目录。然后把data.txt也拷过去整个文件夹就可以打包成zip分发了。如果程序用到了QPainter绘制本项目肯定用了windeployqt默认会带上platforms目录没有它程序双击会报“could not find the qt platform plugin windows”错误。如果出现这个检查一下exe目录下有没有platforms/qwindows.dll没有就手动从Qt安装目录拷贝。5.3 发布后的输入法问题和运行报错发布后的程序在部分中文Windows上可能出现输入法切换异常或字体不对解决方法是给程序加一个高DPI声明。在main.cpp里最前面加#include QApplication int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); // ... }这句代码必须在构造QApplication之前调用否则无效。另外发布版的exe如果报缺少libstdc-6.dll或libgcc_s_seh-1.dll说明MinGW运行时库没带上从C:\Qt\Tools\mingw810_64\bin下拷贝到发布目录即可。6. 高频报错与排查技巧实录6.1 fata1cannot mix incompatible Qt library这个报错原话一般是fatal: cannot mix incompatible Qt library (version ex50601) with this library意思是你的程序链接的Qt库和运行时加载的Qt库版本不一致。最常见的触发场景你用Qt 5.15.2的库编译但系统PATH里混入了另一个版本的Qt DLL。解决思路就三步检查构建套件里选的Qt版本和实际安装的是否一致打开命令行运行where Qt5Core.dll查看系统搜到的是哪个路径的库把exe目录下的Qt DLL清理掉重新用windeployqt部署确保所有DLL来自同一个Qt目录。之所以这个报错高发是因为新手可能装了多个版本的Qt比如5.12和5.15并存一不留神PATH或构建目录配混了。建议一台开发机只装一个Qt版本至少开发同一个项目时只用一个。6.2 could not find the Qt platform plugin linuxfb如果在Linux或树莓派环境开发运行Qt程序时报这个错qt.qpa.plugin: could not find the Qt platform plugin linuxfb意思是Qt没有找到合适的平台插件。Windows下是windows插件Linux下一般是xcb或linuxfb。解决方式export QT_QPA_PLATFORMxcb或者在代码里qputenv(QT_QPA_PLATFORM, xcb);但注意要放在QApplication构造之前。如果嵌入式设备确实需要linuxfb则需要编译安装对应的Qt插件。这个报错多数情况下是环境变量没设导致的不是代码bug。6.3 中文乱码MSVC和MinGW的编码差异在MSVC下写Qt程序如果源码里有中文字符串编译器默认按GBK解析但Qt内部用的是UTF-16所以经常会显示乱码。解决方式有两种在pro文件里加编译选项QMAKE_CXXFLAGS /utf-8或者在所有包含中文字符串的源文件顶部加一句话#pragma execution_character_set(utf-8)MinGW一般默认UTF-8乱码问题少很多。这也是我推荐新手用MinGW的原因之一。此外打开文件读取中文内容时建议统一用QTextStream::setEncoding(QStringConverter::Utf8)或者setCodec(UTF-8)。6.4 程序闪退与访问冲突0x0000005很多新手操作到一半程序直接闪退日志里写着异常码0xc0000005Access Violation。这类问题90%是空指针解引用或野指针。典型场景你new了一个子控件但还没addWidget到布局里就直接访问它的成员连接了信号槽之后控件被提前delete了触发槽时访问已释放内存容器访问越界比如stationList[i]而i超过了size()。排查闪退我习惯这样做先用调试模式跑一遍Qt Creator会在崩溃点停下来查看调用栈确认是哪个文件哪一行。如果是release模式可以在关键位置加qDebug()打印日志逐步定位。永远不要不定位就瞎改那样只会越改越乱。6.5 Qt Creator里运行正常但双击exe闪退这在发布版里非常常见。Qt Creator里能跑是因为它设置了正确的PATH环境变量exe运行时能加载到DLL。但双击exe时PATH里没那些DLLQt平台插件加载不到就直接退出。检查步骤确认exe目录下有platforms/qwindows.dll确认需要的Qt DLL都在exe目录下打开cmdcd到exe目录再运行看有没有命令行报错输出。实际上99%的“双击闪退”都是部署不全导致的而不是代码问题。用windeployqt完整部署一遍基本能解决。7. 避坑心得与进阶扩展方向7.1 先画草图再写代码我最大的体会是做带图形的程序一定要先在纸上画出界面草图标清楚每个区域的功能再开始写代码。这能帮你提前发现很多问题。比如你可能一开始没意识到查询结果出来后模拟区需要及时刷新地图这个联动在做界面草图时就会发现。用代码来思考界面设计结果往往是在痛苦的反复修改中度过的。7.2 数据驱动的界面设计如果你只想做一个“能用”的系统把数据写死在代码里就够了。但如果你想做一个“好看好用”的系统一定要做成数据驱动。所谓数据驱动就是界面上展示的一切内容都由内部数据决定数据变了界面自动跟着变而不是每个变化都手动去改控件的值。实现数据驱动最核心的一点数据和界面之间靠信号/槽或事件驱动更新。数据一变就发一个dataChanged信号出来界面层收到后刷新对应区域。这个模式一开始写会觉得多花了点代码但后续扩展功能、修bug时省下的时间远大于投入。7.3 代码里多留注释尤其是算法部分Dijkstra、换乘逻辑这种地方一个多月后回来看很可能自己都看不懂了。多写注释说明思路不仅方便自己答辩时老师翻代码也会觉得你的工程素养不错。注释不需要写散文说明清楚为什么这么写就够。7.4 图形展示的拓展QChart与数据库做完基础功能后如果你想让它看上去更“高级”可以考虑两个扩展第一用QChart把票价/里程数据做成图表。比如查询结果旁边放一个柱状图直观对比不同车次的价格。QChart使用不复杂本质上就是把数据塞进QBarSeries再设置到QChartView。要注意的是Qt Charts模块是独立的pro文件里需要加QT charts安装组件时要勾选对应的模块。第二把数据层从文本文件换成SQLite数据库。Qt内置了SQL模块接上之后不仅查询速度和灵活性大幅提升还能支持更复杂的条件筛选。操作数据库的代码不多构造QSqlDatabase、执行QSqlQuery配合QSqlTableModel可以直接绑定到TableView。7.5 答辩演示的节奏控制这个系统做出来最终是要给老师演示的。我的建议是准备好一份“演示脚本”先展示整个界面的结构和功能再从查询开始演示直达线路然后演示一个需要中转的查询接着演示模拟运行的过程配合地图上的移动效果最后展示打包后的exe能独立运行。整个流程控制在5-8分钟。有几点细节要提前检查演示机的分辨率最好和开发机一致避免界面显示不全字体缩放别太大否则控件会错位模拟动画的速度要调合适太慢显得卡太快看不清。做这个项目最大的收获不是“我写了一个系统”而是建立起了“把需求和界面落成代码”的完整思维链条。从拆解需求、设计数据结构、实现核心算法到用Qt把逻辑变成可视化交互整个过程走一遍你对C和Qt的理解会有一个质的提升。实际开发中遇到的每个报错都在逼你去看文档、翻源码、理解框架的运行机制这些能力远比项目本身更有价值。最后分享一个我自己的小习惯每实现一个功能模块就提交一次代码注释把当时为什么这么写、踩了什么坑记录下来。答辩前的准备周里这些注释就是最好的复习材料。希望这份实操笔记能帮你把这个项目顺利做出来少走些弯路。