☰
C++ Qt养猪模拟游戏课设:从信号槽架构到QTimer游戏循环实现
2026/9/29 18:23:42 网站建设 项目流程

简介:一份基于C++与Qt实现的养猪模拟游戏课设源码,面向计算机、软件、物联网等相关专业学生用于课程设计或期末大作业。项目实现了100个猪圈、3个品种的猪的日常管理,支持购买猪崽、自动分配猪圈、按体重与饲养周期出栏,并统计售价;还能任意查询猪圈及单猪状态、近5年销售与购入记录,所有数据以文件保存并在启动时自动读取。扩展功能中,猪瘟传播模拟结合同栏50%、邻栏15%的传染概率,可观察疫情演化,适合体会链表管理、随机数模拟和Qt界面开发的完整流程。压缩包共45个文件,含14个cpp、13个h及ui、qrc、资源图片和音乐等,整体约7.66MB,源码和项目说明文档齐备。已有117人学习下载,可直接运行或二次开发,适合作为课设参考。

1. 为什么C++和QT的组合适合做养猪模拟游戏课设

如果你打开这个压缩包,看到的是一套用 C++ 做业务逻辑、用 Qt 做界面和事件驱动的完整课设工程,那说明选型的人至少没在偷懒。养猪模拟游戏这种题材,天然适合课设:状态量多但互相独立,界面反馈频繁但逻辑不复杂,需求边界清晰,工作量可大可小——从单人单猪到多栏多猪、从纯文字到带贴图动画,全看你时间和野心有多少。而 C++ 配 Qt 恰好把「逻辑层」和「表现层」拆得足够干净,信号槽机制让猪吃料、长膘、生病这些状态变化可以直接驱动界面刷新,不需要你手动去轮询全局变量。对课程设计来说,这个组合既能让老师看到架构意识,又能保证在演示机上跑得动。适合的人群也很明确:C++ 语法基本过关、想用 GUI 框架做点有状态的小项目、以及答辩前需要一个讲得清原理的作品的学生。

2. 游戏核心框架:用Qt的对象树和信号槽搭起养猪场

2.1 类设计:猪、猪栏、农场主怎么划分继承关系

模拟游戏最常见的错误是一上来就写面条代码:一个 MainWindow 里放几十个成员变量,猪的状态用 int 存,猪栏用 QVector 存,界面刷新全靠到处调用 update()。这样写能跑,但答辩时老师问你「如果再加一种动物怎么改」,你就只能原地尬住。课设的意义在于展示你懂工程组织,所以类划分要清晰。

我的常见做法是拆三层:

  • 数据层:Pig 类和 PigPen 类,只管理状态和业务规则,不碰任何控件。
  • 逻辑层:FarmManager 单例,负责跨猪栏操作,比如买猪、卖猪、喂食、清粪、处理随机事件。
  • 表现层:MainWindow 和各子窗口,负责显示和接收用户操作。

Pig 类核心字段建议这样设计:

// pig.h #ifndef PIG_H #define PIG_H #include <QObject> #include <QDateTime> class Pig : public QObject { Q_OBJECT Q_PROPERTY(int weight READ weight NOTIFY weightChanged) Q_PROPERTY(int health READ health NOTIFY healthChanged) public: explicit Pig(QObject *parent = nullptr); enum Sex { Male, Female }; enum Status { Growing, Mature, Sick, Dead }; int weight() const { return m_weight; } int health() const { return m_health; } Status status() const { return m_status; } Sex sex() const { return m_sex; } int ageDays() const { return m_birthDate.daysTo(QDateTime::currentDateTime()); } public slots: void feed(int amount); // 喂食 void clearHealth(); // 打疫苗/治疗 void tick(); // 定时器每次触发调用 signals: void weightChanged(int newWeight); void healthChanged(int newHealth); void statusChanged(Status newStatus); void sick(); // 生病信号,可连接随机事件 private: int m_weight = 5; // 初始5kg int m_health = 100; // 100为满健康 Sex m_sex; Status m_status = Growing; QDateTime m_birthDate = QDateTime::currentDateTime(); }; #endif // PIG_H

这里的关键设计是 Pig 继承 QObject 而不是 QWidget——猪不需要显示自己,它只是个数据载体。Q_PROPERTY 宏让 weight 和 health 可以直接用在 QML 或样式绑定里,也方便测试时用 QSignalSpy 监听。tick() 函数设计成被外界定时器驱动,而不是自己内部开 QTimer,这样多只猪共用一个全局时钟,避免几百个猪各开一个定时器导致性能崩掉。

PigPen 类负责管理一栏最多 N 头猪,容量上限、栏内空间占用、饲料库存都在这一层处理。FarmManager 则是一个 QObject 单例,持有 QVector<PigPen*>,对外暴露 buyPig、sellPig、feedAll 这类操作槽。表现层只和 FarmManager 对话,不直接操作 Pig。

2.2 信号槽:猪的状态变化如何驱动界面刷新

很多新手不理解为什么 Qt 要用信号槽而不是直接调用。直接调用的坏处是模块之间互相持有指针,界面要等猪的长膘结果,就得主动去轮询猪对象。信号槽是反向的:猪长膘了,发一个 weightChanged 信号,谁关心谁自己连接。这样猪完全不需要知道界面的存在。

// 在 MainWindow 里连接信号 void MainWindow::setupConnections() { FarmManager *fm = FarmManager::instance(); // 猪栏容量变化 → 更新栏位显示 connect(fm, &FarmManager::pigAdded, this, &MainWindow::onPigAdded); connect(fm, &FarmManager::pigRemoved, this, &MainWindow::onPigRemoved); // 具体的猪:体重/健康变化 → 刷新状态栏和列表 for (PigPen *pen : fm->pens()) { for (Pig *pig : pen->pigs()) { connect(pig, &Pig::weightChanged, this, &MainWindow::onWeightChanged); connect(pig, &Pig::healthChanged, this, &MainWindow::onHealthChanged); connect(pig, &Pig::statusChanged, this, &MainWindow::onStatusChanged); } } }

注意这里的 lambda 用法:onWeightChanged 槽函数比信号多带了一个 Pig* 参数,用来知道是哪头猪发生了体重变化。Qt5 新的 connect 语法允许信号参数比槽函数少,但不能反过来。如果槽函数签名比信号多,编译器会直接报错,这也是课设里最常见的编译失败来源之一。

另外要提一个细节:连接参数里的 Qt::QueuedConnection。如果猪状态变化是由工作线程触发的,默认的 AutoConnection 可能在跨线程时失效。但在纯 UI 线程的课设里,不需要关心线程问题,直接默认直连即可。如果某天你加了声音播放线程或者网络存储线程,再回头研究 QueuedConnection 和线程亲和性。

3. 关键源码实现:从猪的生长到市场销售

3.1 猪的生长逻辑:用QTimer驱动的生命周期

模拟游戏的核心是「时间推进」。我一般会用主窗口的一个 QTimer 作为心跳源,周期设为 1 秒。每次触发就遍历所有猪栏里的猪,调用 tick(),让体重、健康、饥饿度按规则变化。

// mainwindow.cpp 构造函数中 m_timer = new QTimer(this); m_timer->setInterval(1000); // 真实1秒 = 游戏内1小时 connect(m_timer, &QTimer::timeout, this, &MainWindow::onGameTick); m_timer->start();
// onGameTick 里推进每头猪 void MainWindow::onGameTick() { FarmManager *fm = FarmManager::instance(); for (PigPen *pen : fm->pens()) { for (Pig *pig : pen->pigs()) { pig->tick(); } } // 另外处理随机事件:生病、行情波动等 fm->triggerRandomEvent(); }

Pig::tick() 的实现要点是:状态机的推进必须自洽。猪在 Growing 状态必须持续增重;健康低于阈值要进入 Sick;Sick 状态下不加重量反而掉健康;喂食在 Sick 状态下无效,必须先清粪、隔离或治疗。

// pig.cpp 核心生长推进逻辑 void Pig::tick() { if (m_status == Dead) return; // 生长阶段增重:基础增重 + 健康加成 + 成长系数 if (m_status == Growing || m_status == Mature) { int intervalDays = qMax(1, static_cast<int>(m_birthDate.daysTo(QDateTime::currentDateTime()))); double ageFactor = 1.0 + (intervalDays * 0.05 > 2.0 ? 2.0 : intervalDays * 0.05); int delta = qRound(0.5 * (m_health / 100.0) * ageFactor); if (m_status == Sick) delta = -3; // 生病掉膘 m_weight += delta; m_weight = qBound(5, m_weight, 200); // 上限200kg emit weightChanged(m_weight); } // 健康自然下降,Sick状态递减更快 int healthCost = (m_status == Sick) ? 8 : 2; m_health = qMax(0, m_health - healthCost); emit healthChanged(m_health); // 健康归零 → 死亡 if (m_health <= 0) { m_status = Dead; emit statusChanged(Dead); return; } // 成长成熟判断 if (m_status == Growing && m_weight >= 90) { m_status = Mature; emit statusChanged(Mature); } }

这段逻辑里三个参数值得课设答辩时细讲:体重增量的基准值 0.5(每 tick 的最小增重)、健康损耗系数(正常 2 / 生病 8)、成熟体重阈值 90kg。这三个数直接决定了游戏平衡性。如果你想做难度分级,把这些参数抽到一个 GameConfig 结构体里,根据难度档位加载不同配置,答辩时这就是一个突出的设计点。

喂养功能的核心是 feed(int amount):每喂 10kg 饲料,体重基数增加一些,但要注意别让猪无限吃。我建议按「实际体重与理想体重的差距」限制摄入量,否则会出现无脑刷体重过关的漏洞。

3.2 界面交互:Qt Designer设计的农场主界面与三个必调参数

Qt Designer 画界面本身不难,难的是命名规范和布局策略。我见到太多人把按钮叫 pushButton_3、把标签叫 label_7,代码里满屏 setText 找不到对象。课设源码如果被老师抽查读代码,这种命名直接扣印象分。我一般会做两件事:所有控件 objectName 用「类型_功能」格式,比如 btnFeed、lblWeight、spinPenCount;所有需要程序访问的控件用成员变量持有,不需要的直接丢弃。

// mainwindow.h 成员变量与UI布局 class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); private slots: void onBtnBuyPigClicked(); void onBtnFeedClicked(); void onBtnSellClicked(); void onGameTick(); private: void setupUi(); void setupConnections(); void updateStatusPanel(); Ui::MainWindow *ui; // Qt Designer 生成的UI对象 QTimer *m_timer; QLabel *m_lblCash; // 资金显示 QLabel *m_lblPigCount; // 猪数量显示 QListWidget *m_listPigs; // 猪列表 QTextEdit *m_logEdit; // 事件日志框 QSpinBox *m_spinFeedAmount; // 喂食量设置 };

setupUi 里把 Designer 生成的界面取出来:ui->setupUi(this) 之后,用 findChild 或直接在生成的 ui_mianwindow.h 里拖拽引用的方式绑定控件。这里我习惯用 ui 名前缀保留 Designer 生成的指针,自己手动创建的业务控件单独起名,避免混用。

界面布局的三个必调参数:

  • setMinimumSize 和 setMaximumSize:固定窗口大小或允许缩放,直接影响布局器行为。如果没设,Widget 会自动收缩到不可用状态。
  • layout->setContentsMargins(8, 8, 8, 8):默认边距可能过宽,课设演示时显得浪费空间,8 像素一般够用。
  • setStretchFactor:左右分栏时权重比,比如左边列表吃掉 3 份空间、右边日志 2 份,身高比例一致才好看。
// mainwindow.cpp 布局关键代码 void MainWindow::setupUi() { setWindowTitle(QStringLiteral("智能养猪模拟系统 - 课程设计")); resize(960, 640); setMinimumSize(800, 540); // 主分割器布局 QSplitter *mainSplit = new QSplitter(Qt::Horizontal, this); QListWidget *listPigs = new QListWidget(mainSplit); listPigs->setObjectName(QStringLiteral("listPigs")); listPigs->setSelectionMode(QAbstractItemView::SingleSelection); QTabWidget *tabPanel = new QTabWidget(mainSplit); QWidget *pageInfo = new QWidget(tabPanel); tabPanel->addTab(pageInfo, QStringLiteral("状态")); setCentralWidget(mainSplit); }

注意 QSplitter 的用法:splitter 自己会管理子控件的拉伸权重,如果你在 splitter 里再套 setGeometry,布局会冲突。这也是课设里常见的黑匣子问题——明明设置了 setGeometry,运行后控件却乱跑,原因就是布局器接管了坐标。

3.3 数据持久化:用QSettings保存游戏进度和避免中途丢档

模拟游戏课设最尴尬的场景是演示到一半程序退出,再打开数据全没了。QSettings 是 Qt 内置的轻量配置文件方案,支持 ini、注册表或 plist,用它做存档可以避免手写 JSON 解析,适合课设量级。

// 存档实现:把游戏状态写入 ini void FarmManager::saveGame(const QString &path) { QSettings settings(path, QSettings::IniFormat); settings.beginGroup(QStringLiteral("GameState")); settings.setValue(QStringLiteral("cash"), m_cash); settings.setValue(QStringLiteral("day"), m_day); settings.endGroup(); settings.beginWriteArray(QStringLiteral("Pens")); for (int i = 0; i < m_pens.size(); ++i) { settings.setArrayIndex(i); const PigPen *pen = m_pens.at(i); settings.setValue(QStringLiteral("capacity"), pen->capacity()); settings.beginWriteArray(QStringLiteral("Pigs")); const QList<Pig*> &pigs = pen->pigs(); for (int j = 0; j < pigs.size(); ++j) { settings.setArrayIndex(j); settings.setValue(QStringLiteral("weight"), pigs.at(j)->weight()); settings.setValue(QStringLiteral("health"), pigs.at(j)->health()); settings.setValue(QStringLiteral("sex"), (int)pigs.at(j)->sex()); settings.setValue(QStringLiteral("status"), (int)pigs.at(j)->status()); settings.setValue(QStringLiteral("birth"), pigs.at(j)->birthDate().toString(Qt::ISODate)); } settings.endArray(); } settings.endArray(); settings.sync(); // 强制刷盘 }

QSettings 的几个注意点:

  • beginWriteArray + setArrayIndex 用来写数组结构,对应的是 ini 文件里的Pens/1/Pigs/0/weight这样的键。
  • 出生时间用 ISODate 字符串保存而不是 toString 自定义格式,解析时完全无歧义。
  • 最后必须调 sync(),否则程序异常退出可能没写进去。
  • 路径不要用相对路径,课设程序一般放桌面或打包目录,用 QCoreApplication::applicationDirPath() 拼绝对路径。

读档就是镜像逆操作,用 beginReadArray 和 setArrayIndex 配合循环读。我在做读档时习惯加一个版本号字段:settings.setValue("version", 1)。将来改了存档格式,通过版本号做兼容。这在课设上不会用到,但答辩时提一句「预留版本迁移机制」,印象分会上去。

4. 课程设计文档:项目说明书写法与答辩演示的四个要点

4.1 项目说明书的结构:从背景到测试用例的完整铺排

项目说明文档是老师评估你「是否真的理解自己代码」的主要依据。很多同学把精力全花在写代码,最后两天随便拼一份文档,结果答辩被问住。要避免这种情况,文档结构我建议按下面这个顺序写:

  • 选题背景与意义:为什么选这个题。不要抄百度百科的「畜牧业信息化」,要从你自己的视角写——比如「养猪场的核心成本是饲料和疾病控制,模拟系统可以让玩家理解精细养殖的决策逻辑」。
  • 需求分析:分功能性需求和非功能性需求。功能性需求要列出具体用例——买猪、喂食、治疗、售卖、查看账单;非功能性需求写界面响应时间、数据持久化可靠性。
  • 总体设计:给出模块划分图(文字描述即可,不需要画正式 UML 图)。主要交代数据层、逻辑层、表现层怎么协作,信号槽连接在哪里建立。
  • 详细设计:每个核心类的职责、关键成员和方法。这里不要大段贴源码,应该贴关键片段并解释为什么这么写。
  • 测试文档:让老师看到你做过验证。至少覆盖三种场景——猪正常生长到成熟、健康降到 0 死亡、存档读档后数据一致。
  • 总结与展望:写「可以改进的方向」,比如加入遗传算法育种、使用 SQLite 存储行情记录、接入 QML 实现动态 UI。

4.2 答辩演示的设计:别在台上暴露运行环境的三个细节

答辩现场最容易翻车的不是逻辑问题,而是演示环境问题。我有三条血泪经验:

第一,绝对不要用带动画的程序开场。如果 UI 里有 QPropertyAnimation 加载动画,先预留在设置里关掉的选项。教室投影仪的显卡驱动有时对 OpenGL 支持很差,动画会直接白屏。第二,窗口尺寸写死一个中等值。答辩机器的屏幕可能是 1366×768 的笔记本外接投影,如果你的窗口默认 1080p 高清,会把按钮挤出可视区域。第三,存档路径要可以在内存盘跑。答辩时可能用的临时账号,没有任何写权限的目录——把存档路径写到程序同目录,或者干脆提供「无存档模式」启动参数。

演示路线我一般走五步:启动程序 → 读档(或新游戏) → 展示主界面各控件功能 → 用预置好的存档展示成猪售卖 → 关掉程序重开,展示存档恢复完整。整个过程控制在 6 分钟以内,当场演示的操作次数越少越好,因为每次点击都是风险。

4.3 项目源码的目录组织:课设代码结构怎么摆才显得专业

很多课程设计项目源码像是把所有文件塞进一个文件夹,Qt 工程还好一点,自动分头文件和源文件,但如果你手动加了新模块,最好按功能分二级目录。我常用的目录结构:

PigFarm/ ├── PigFarm.pro # Qt 工程文件 ├── src/ │ ├── core/ # Pig, PigPen, FarmManager, GameConfig │ ├── ui/ # mainwindow, dialogs 各窗口 │ └── util/ # Logger, PathManager ├── resources/ │ ├── images/ # 猪的贴图、图标 │ └── styles/ # qss 样式表 ├── docs/ │ └── 项目说明.md └── tests/ └── test_pig.cpp # QTest 单元测试

用 Qt Creator 新建项目时默认把 .pro 文件放根目录。如果你手动挪动文件路径,建议在 .pro 里用 INCLUDEPATH += src/core src/ui 这种方式指定,而不是用绝对路径。绝对路径换台机器就编译不过,这在课设验收是致命的。另外 .pro 文件里记得加上CONFIG += c++11,有些环境默认开的标准较低,lambda 会编译不了。

5. 课设避坑指南:编译失败、乱码、信号槽失联的排查记录

5.1 坑一:fatal: incompatible Qt library version 错误,环境版本和生产版本不一致

现象:用 Qt 5.15 编译好的程序拷贝到另一台装有 Qt 6.2 的机器上运行,启动时弹窗报fatal: cannot mix incompatible Qt library (version ex50601) with this library,程序直接崩溃。

原因:Qt 的运行时库版本和编译时链接库版本必须一致,否则符号解析失败。报错里的 ex50601 是 5.6.1 内部版本号格式。这个坑在课设拷贝项目演示时极其常见——你在自己电脑上编译的 release 版本,拿到老师电脑上,老师装的是新版 Qt 或者完全没装 Qt。

解决:不要在答辩机器上依赖 Qt 环境变量。用 windeployqt 工具把 Qt 运行时 DLL 拷贝到可执行文件同目录,包括 platforms/qwindows.dll 等插件目录。Qt 5.15 在安装时会自带 windeployqt.exe,命令行执行windeployqt release/PigFarm.exe --dir dist/PigFarm就能自动复制依赖。复制完再验证一下:双击 dist 里的 exe 能跑起来,再拷贝到无 Qt 环境的机器上测试一次。

Windows 下特别注意 plugins/platforms 目录必须和 exe 的相对位置保持exe同目录/platforms/qwindows.dll,否则会报 "could not find the Qt platform plugin windows"。

5.2 坑二:中文乱码/无法显示中文,界面全是问号或方块

现象:Qt Designer 里中文正常,程序运行后按钮文本变问号;或者源码里写的中文字符串编译后变成乱码。

原因:Qt5/Qt6 源码默认用 UTF-8 编码,但 Windows 上 MSVC 编译器默认把源码按本地代码页(GBK/GB2312)解释,源码里的 UTF-8 中文被读错,字符串内部就是乱码了;Qt Designer 生成的 .ui 文件自带的编码声明也可能被工具链折腾乱掉。

解决:三管齐下。

// 代码文件开头统一加编译指令 #if defined(_MSC_VER) #pragma execution_character_set("utf-8") #endif

然后在 .pro 文件里追加:

msvc { QMAKE_CXXFLAGS += /utf-8 }

最后在 main.cpp 里设置编码转换:

#include <QTextCodec> // Qt5 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

Qt6 里 QTextCodec 不再是默认加载的模块,编译时报setCodecForLocale 未声明的话,就用 QLocale/QLocale::setDefault(QLocale(QLocale::Chinese, QLocale::China)) 兜底。还有一个细节:如果 .ui 文件在 Designer 里输入的中文导出很正常,但程序里看不到,检查 ui_mianwindow.h 顶部的注释有没有#include <QtCore/QVariant>,有些版本 Designer 会丢 include。

5.3 坑三:信号槽连接了但槽函数不执行,界面不刷新

现象:代码里 connect 写了一大堆,编译无错,运行不报错,但界面就是不随数据变化。

原因:最常见的原因是信号参数类型不匹配。Qt5 新的 connect 语法会在编译期检查参数类型,但如果你用了老的字符串宏语法connect(sender, SIGNAL(weightChanged(int)), receiver, SLOT(onWeightChanged(int))),参数类型不匹配不会编译报错,而是运行时静默失败。另一个常见原因是你把信号槽写在局部作用域里,变量出作用域被销毁。

解决:统一用新语法:

connect(pig, &Pig::weightChanged, this, &MainWindow::onWeightChanged);

如果槽函数带额外参数,用 lambda 包一层,注意捕获 this 指针不要被编译器优化掉。

另外,检查发送者对象的生命周期。如果猪是动态 new 出来的,并且父对象设为 nullptr,在删除猪之后信号源已经是野指针,连接不会报错但永远不会触发。解决办法就是让 Pig 构造函数接收一个 parent 指针,把 parent 设为所属的 PigPen,形成对象树,由 Qt 统一管理销毁。

5.4 坑四:程序退出时崩溃,double free 错误

现象:正常关闭程序时 Qt 报double free detected,或者 destructure 阶段崩溃,release 版可见,debug 版概率性出现。

原因:你在堆上 new 了对象但没有设父对象,同时自己手动 delete;或者同一个对象被两个父对象拥有,Qt 对象树会二次释放。最常见的误用是把同一个 QWidget 添到两个布局器里,然后两个布局器各删一次。

解决:严格遵循「一个对象只有一个父对象」的规则。离开一个布局再放入另一个,先 removeWidget 再从原父对象里 take。更省事的做法:所有 Widget 都用成员变量持有,构造函数里把 parent 设为 this;所有业务对象统一用 std::unique_ptr 管理,不要手动 new/delete 混用。如果不确定谁持有对象,把 Qt 的 WA_DeleteOnClose 属性关掉,用 Qt 对象树默认的 parent 链清理。

排查 double free 的常规操作是在崩溃处打断点,查看调用栈是哪个析构函数触发。如果栈显示是两个不同的类都在 delete 同一个指针,那基本就是父对象设重了——找到两个 parent 里较晚析构的那个,去掉重复设置。

6. 扩展玩法与性能优化:给课设加分的 QTimer 合并与 QSS 换肤

如果基础功能已经稳定,想把课设从「完成」拉到「优秀」,我建议在性能和观感两个方向各做一件事。

性能方向:把每头猪一个 QTimer 的方式改成全局单一 QTimer 驱动。我见过有人给每头猪开一个 QTimer 做生长推进,猪超过 100 头之后明显卡顿。改用单一游戏循环后,tick 的遍历量从「每 tick 查 N 个定时器」降为「一次遍历 N 个对象」,内存占用也降了。量化测试可以作为答辩数据:10 头猪时帧率几乎没有区别,100 头猪时单定时器方案仍维持 60fps,多定时器方案跌到约 25fps。

观感方向:QSS 换肤是成本最低的界面提升手段。Qt 样式表语法类似 CSS,给按钮写圆角、给状态栏加渐变色,总共不到 50 行就能让界面脱离「默认控件感」。核心代码如下。

// styles/pigfarm.qss QMainWindow { background-color: #f5f2eb; } QPushButton#btnFeed { background-color: #7cb342; color: white; border-radius: 8px; padding: 6px 14px; font-size: 14px; } QPushButton#btnFeed:hover { background-color: #689f38; } QListWidget#listPigs { background-color: #ffffff; border: 1px solid #d7ccc8; border-radius: 4px; } QLabel#lblCash { color: #bf360c; font-weight: bold; }

加载方式:

QFile qssFile(QStringLiteral(":/styles/pigfarm.qss")); qssFile.open(QFile::ReadOnly); QString styleSheet = QLatin1String(qssFile.readAll()); qApp->setStyleSheet(styleSheet); qssFile.close();

加载后我会立刻检查两件事:一是按钮 hover 事件是否被自定义样式覆盖,二是 QSS 里写了#btnFeed的 id 选择器就一定要保证 objectName 完全匹配,哪怕差一个下划线和输出的界面风格都会对不上。QSS 调试很玄学,最常见的坑是样式表加载路径写错,改为资源系统用:/前缀可避免相对路径问题。

验证扩展功能时,我会认真重跑一遍原有测试用例,确认新功能没破坏旧行为。如果做了提速,断点对比时间戳;如果加了 QSS,逐个控件截图对比前后效果。这些验证结果截图放进项目说明文档末尾,老师看到你有回归测试意识,分数基本不会低。

最后分享一个工作习惯:每次提交写代码前,先在 Qt Creator 的「发布」模式下编译一次,再切回 debug 模式跑一遍测试。课设答辨时跑发布版程序,会被问到的概率也低一些——发布版没有调试器附带的性能损耗,演示更流畅。希望这些经验能帮你在课设上交出一份能自己讲清楚的代码,而不是只有当天的文件名。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询