
简介一套面向数据库系统课程设计的酒店管理系统完整项目基于 Python PyQt5 MySQL 实现 GUI 编程压缩包解压即可运行调试适合高校学生、毕业设计或需要快速搭建管理类系统的开发者使用。项目包含源码、数据库脚本与课程设计报告功能覆盖员工管理、客房管理和客户管理员工可按权限查看信息并添加、修改、删除删除时需校验编号、姓名和身份证号客房支持按条件查询、个人/团队/预订入住、取消预约、退房以及房间增删改查客户入住记录留作数据分析与推荐基础。压缩包共 61 个文件以 Python 脚本18 个 py、界面文件8 个 ui、数据库脚本3 个 sql为主另含《数据库应用》系统设计报告、E-R 图与功能结构图等资料整体大小 8.28MB目录结构清晰。ui 文件可与 py 脚本对应修改便于学习 PyQt5 界面与事件逻辑已有 209 人浏览学习适合期末课设、毕业设计或二次开发参考。1. 课设科目与工程范围为什么选 Python PyQt5 MySQL很多学校的数据库课程设计题目一眼看过去都是行政管理系统的变体酒店管理系统、宾馆客房管理系统、民宿预定平台换汤不换药。核心要求就三句话——设计数据库表并写入有效数据做一个带图形界面的管理端最后交一份能讲清楚流程的课程设计报告。基于 Python PyQt5 MySQL 的酒店管理系统是这条路上最不折腾人的技术组合Python 负责业务逻辑PyQt5 负责 GUI 编程把登录、选房、入住登记、退房结账这些窗口画出来MySQL 负责把房间、客户、入住记录存下去。对动手能力一般、时间又紧的同学来说这套方案代码量可控、排错资料多、演示效果好课设报告里也好画架构图。这个标题想解决的问题很明确拿到源码和数据库脚本后能不能在自己电脑上把 MySQL 服务起起来把建库脚本导进去再运行主程序看到登录窗口到主界面之间每一个按钮都真实可用而不是跑十分钟就崩。适合正在做数据库课设或毕业设计、目标评分标准里包含“可运行演示”的人。接下来的内容就是按“环境搭建 → 建库 → 界面与业务 → 避坑 → 答辩验证”这条路径把整套方案讲透。2. 环境与工程骨架装好三件套后先把一个能正常关闭的 PyQt5 窗口跑出来2.1 版本选型Python、PyQt5、MySQL 之间最容易打架先定版本再动手装。我的建议是 Python 3.10 或 3.11PyQt5 5.15.xMySQL 8.0连接库用 pymysql 1.1.0 以上。PyQt5 官方在 5.15 之后就停止了新功能迭代但对课设来说功能完全够用而且 5.15 版本的 wheel 包对 Python 3.8~3.11 都有预编译版本pip 直接装不会要求本地编译这也是它比 PySide6 更省心的原因之一。MySQL 选 8.0 是因为在 Windows 上安装包有图形化的 installer初始化 root 密码和改端口都很直观5.7 也行但网上很多旧教程的语句在 8.0 上会报认证插件错误反而添乱。pymysql.connect 走的是原生 MySQL 协议不需要像 MySQLdb 那样依赖 C 扩展pure Python 实现Windows 和 Linux 都能直接 import。不要图新鲜用 mysql-connector-python它和 PyQt5 配合时经常出现连接不释放导致界面卡死的情况排错成本比 pymysql 高。编辑器方面直接用 PyCharm 或者 VS Code配置好 python 环境路径即可这两个 IDE 的终端里跑 pip 和 python 不会出现“命令不存在”的尴尬。2.2 安装命令换源解决一半的安装报错pip 直接装 PyQt5 本身不难难的是国内网络环境下从官方 PyPI 源拖几十 MB 的 wheel 包经常超时装到一半显示“Connection broken”或“Read timed out”这就是新手第一次翻车的重灾区。用清华镜像一次性装完三件套最稳妥python -m pip install PyQt5 PyQt5-tools pymysql -i https://pypi.tuna.tsinghua.edu.cn/simplePyQt5-tools 会额外带上 designer.exe后面画 登录界面和主界面的 .ui 文件会用到。如果电脑上同时装了多个 Python务必用python -m pip而不是裸写pip确保装到当前解释器。装好后不要在 IDE 里急着打开主程序先在命令行做一次环境验证python -c from PyQt5.QtWidgets import QApplication; print(PyQt5 OK) python -c import pymysql; print(pymysql.__version__)出现版本号说明 PyQt5 导入正常。如果你看到 import 时弹 “DLL load failed while importing QtCore”十有八九是 PyQt5 版本和 Python 版本错位卸载重装一个匹配的版本即可别去改系统 DLL 路径。2.3 工程目录骨架源码、数据库脚本、课程设计报告分开放课设答辩时老师很可能直接打开你的文件夹检查目录层级。习惯上我会建这样一套结构源码和文档分离数据库脚本单独放一个 db 目录HotelMS/ ├── app/ │ ├── main.py # 程序入口 │ ├── login_window.py # 登录窗口 │ ├── main_window.py # 主界面 │ ├── ui_login.py # 由 Qt Designer 生成的登录界面 │ ├── ui_main.py # 由 Qt Designer 生成的主界面 │ ├── db/ │ │ └── dao.py # 数据库连接封装与增删改查 │ └── widgets/ # 自定义控件如房间状态表格 ├── db/ │ ├── hotel.sql # 建库、建表、初始化数据一体脚本 │ └── er_diagram.png # E-R 图报告配图 ├── docs/ │ └── 课程设计报告.md └── requirements.txtmain.py 控制在 30 行以内只负责创建 QApplication、设置字体、启动登录窗口业务逻辑全部拆到 dao.py 和各个 window 文件里。这样做的好处是答辩被问到“这块逻辑怎么改”时你不用在 1000 行的单文件里上下翻。2.4 最小可运行窗口先跑通再谈业务不要一上来就堆整个系统先把一个最小窗口跑起来。下面这段代码是 GUI 编程里最常见的 QMainWindow 骨架所有后续页面都在它上面扩展import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(酒店管理系统) self.resize(1024, 768) label QLabel(数据库连接测试通过后这里会变成房间状态面板, self) self.setCentralWidget(label) if __name__ __main__: app QApplication(sys.argv) font app.font() font.setFamily(Microsoft YaHei) # Windows 下默认字体容易变方块 app.setFont(font) win MainWindow() win.show() sys.exit(app.exec_())这段代码有两个容易被忽略的点。app.setFont在创建窗口之前设置是为了避免 PyQt5 在无中文字体的系统上把所有汉字画成一排横线win.show()之后调用app.exec_()进入事件循环窗口才能响应关闭按钮。如果连这一步都没跑通先别碰数据库说明 PyQt5 环境本身有问题。3. 数据库设计与连接层建表脚本、初始化数据与 pymysql 连接封装3.1 核心表设计房间、客户、入住登记、退房结账酒店管理系统再简单也要至少覆盖“房间状态、客人信息、入住、退房”四个环节。我的设计方案是四张表加一个视图表名用途关键字段room房间档案room_id, room_no, room_type, price, statuscustomer客户档案cid, name, id_card, phone, create_timecheckin在住登记record_id, room_id, cid, checkin_date, expect_date, deposit, statuscheckout退房结账record_id, room_id, cid, checkin_date, checkout_date, total_amount, pay_timeroom 表的 status 用 TINYINT 表示0 代表空房、1 代表已入住、2 代表打扫中配合DEFAULT 0语义明确也能减少字符串判断。不要把客户姓名、证件号直接塞进 checkin 表里反复存储客户信息应当落 customer 表checkin 表和 customer 通过 cid 关联否则一个老客户住三次数据库里就有三行身份证号课后报告里老师看到重复数据会直接扣“数据一致性”的分。checkin 和 checkout 为什么拆开因为退房结账记录是历史流水不允许被后续操作覆盖而在住登记需要频繁修改状态。拆开之后发展客户入住流程是 insert 一条 checkin 并把 room.status 置为 1退房时读取 checkin 里对应的记录计算金额后写一条 checkout再把 room.status 改回 0。每个浴室操作都遵循这个顺序系统就能避开“房间已退状态还是 1”的翻车场景。3.2 建库脚本一段能反复重跑的 hotel.sql数据库脚本的规范是“可重复执行”我习惯在开头加 DROP DATABASE IF EXISTS方便自己在开发过程中反复重置。下面给出最小完整脚本包含建库、建表、初始房间数据DROP DATABASE IF EXISTS hotel; CREATE DATABASE hotel DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE hotel; CREATE TABLE room ( room_id INT PRIMARY KEY AUTO_INCREMENT, room_no VARCHAR(10) NOT NULL UNIQUE, room_type VARCHAR(20) NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0 COMMENT 0空房 1入住 2打扫 ) ENGINEInnoDB; CREATE TABLE customer ( cid INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, id_card VARCHAR(18) NOT NULL UNIQUE, phone VARCHAR(20), create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE checkin ( record_id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL, cid INT NOT NULL, checkin_date DATETIME NOT NULL, expect_date DATE NOT NULL, deposit DECIMAL(10,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 1 COMMENT 1在住 0已退, FOREIGN KEY (room_id) REFERENCES room(room_id), FOREIGN KEY (cid) REFERENCES customer(cid) ) ENGINEInnoDB; CREATE TABLE checkout ( record_id INT PRIMARY KEY AUTO_INCREMENT, checkin_id INT NOT NULL, room_id INT NOT NULL, cid INT NOT NULL, checkin_date DATETIME NOT NULL, checkout_date DATETIME NOT NULL, total_amount DECIMAL(10,2) NOT NULL, pay_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; INSERT INTO room (room_no, room_type, price) VALUES (101, 标准间, 168.00), (102, 标准间, 168.00), (201, 大床房, 238.00), (202, 大床房, 238.00), (301, 套房, 468.00);几个参数必须说明一是DEFAULT CHARACTER SET utf8mb4只建库不指定字符集Windows 上默认会是 latin1写入中文姓名直接变问号二是FOREIGN KEY不强制加但课设答辩时的加分点是“可以不写外键吗”这类追问加了外键能挡住删除正在入住的房间这类误操作三是价格用DECIMAL(10,2)而不是 FLOAT涉及金额的字段用浮点会在计算时出现 0.10.2 的小数误差扣分不值得。初始化数据的房号不建议写太多5 个房间足够演示入住和退房流程。3.3 连接层封装一个 dao.py 管理所有 SQL 访问PyQt5 界面代码和 SQL 语句混在一起会让整个项目没法维护。我习惯把数据库连接单独封装成 dao.py每个业务操作是一个独立方法import pymysql from pymysql.cursors import DictCursor DB_CONFIG { host: 127.0.0.1, port: 3306, user: root, password: 123456, database: hotel, charset: utf8mb4, cursorclass: DictCursor } def get_connection(): return pymysql.connect(**DB_CONFIG) def query_available_rooms(): conn get_connection() try: with conn.cursor() as cursor: sql SELECT room_no, room_type, price FROM room WHERE status 0 cursor.execute(sql) return cursor.fetchall() finally: conn.close()这里的关键参数是DictCursor它让查询结果以字典形式返回界面代码里可以直接写row[room_no]而不需要记忆数字下标。conn.close()放在 finally 里是强制要求否则 PyQt5 界面每次查询都会泄漏一个连接鼠标点十几次入住后数据库连接数就能把你本地 MySQL 拖到假死。如果课设要求更高一点可以在此基础上做连接池但课设规模完全没有必要。字符集参数charsetutf8mb4和建库语句里的 utf8mb4 必须保持一致。只改一边另一边的中文会乱码两边不改登录窗口里输入中文根本存不进去。这三条字符串参数是数据库连接层 90% 中文乱码问题的解药。4. GUI 编程落地房间状态、入住登记与退房结算三个关键页面4.1 主界面框架用 QTabWidget 把功能页面分组登录成功之后进入主界面主界面我采用 QTabWidget 加三个 Tab“房间状态”“入住登记”“退房结算”。QTabWidget 比 QStackedWidget 更适合课设因为它不需要自己写侧边栏导航逻辑切换时默认带上标签页样式。初始化时用下面这段代码构建框架from PyQt5.QtWidgets import QTabWidget, QWidget, QVBoxLayout from PyQt5.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(酒店管理系统) self.resize(1100, 780) self.tabs QTabWidget() self.tabs.setDocumentMode(True) self.room_panel QWidget() self.checkin_panel QWidget() self.checkout_panel QWidget() self.tabs.addTab(self.room_panel, 房间状态) self.tabs.addTab(self.checkin_panel, 入住登记) self.tabs.addTab(self.checkout_panel, 退房结算) self.setCentralWidget(self.tabs)注意setDocumentMode(True)会让标签页更高筛选这是 Windows 下视觉观感比较好的一个开关不加也不影响逻辑。真正的难点不在框架而在“刷新联动”——切到“房间状态”时页面必须立刻显示最新数据。所以每个 Tab 页面内部都要实现一个refresh()方法并在主界面切页时调用。4.2 房间状态面板QTableWidget 与数据渲染房间状态页不需要花哨的动画一张带颜色标记的表格就能把信息讲清楚。将 QTableWidget 的单元格背景色与 room.status 映射空闲绿色、入住红色、打扫灰色。刷新方法核心逻辑如下from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView from dao import query_all_rooms def load_room_table(self): rooms query_all_rooms() self.table.setRowCount(len(rooms)) for i, r in enumerate(rooms): self.table.setItem(i, 0, QTableWidgetItem(str(r[room_no]))) self.table.setItem(i, 1, QTableWidgetItem(r[room_type])) self.table.setItem(i, 2, QTableWidgetItem(f{r[price]:.2f})) status_text {0: 空闲, 1: 入住, 2: 打扫}.get(r[status], 未知) item QTableWidgetItem(status_text) item.setBackground(STATUS_COLOR[r[status]]) self.table.setItem(i, 3, item)query_all_rooms返回字典列表大多数情况下不需要额外解析。变色逻辑通过setItem后再setBackground如果先 setBackground 再 setItem背景色会被新 item 覆盖这是 PyQt5 表格刷新的一个经典顺序坑。刷新时机默认放在 Tab 切换事件里避免单独写一个“立即刷新”按钮到处丢。4.3 入住登记表单数据入库 房间状态更新入住登记页拆成两部分右上角展示可选房间列表左下角是客户信息表单。操作流程是选中空闲房间、填客户姓名和证件号、录入押金、点“确认入住”。这段必须把“客户表插入”和“房间状态更新”放进同一个事务中执行不能先插入客户再改房间否则中途断电会留下一个没有客户的孤儿登记单。def on_checkin_confirm(self): room_id self.selected_room_id() name self.name_input.text().strip() id_card self.id_input.text().strip() if not room_id or not name or not id_card: self.show_warning(请完整填写入住信息) return conn get_connection() try: with conn.cursor() as cursor: cursor.execute( INSERT INTO customer (name, id_card, phone) VALUES (%s, %s, %s), (name, id_card, self.phone_input.text().strip())) cid cursor.lastrowid cursor.execute( INSERT INTO checkin (room_id, cid, checkin_date, expect_date, deposit, status) VALUES (%s, %s, NOW(), %s, %s, 1), (room_id, cid, self.expect_date.date().toString(yyyy-MM-dd), self.deposit.value())) cursor.execute(UPDATE room SET status 1 WHERE room_id %s, (room_id,)) conn.commit() except Exception as e: conn.rollback() self.show_warning(f入住登记失败{e}) finally: conn.close()参数说明要看清三处。一是所有 SQL 都用%s占位符并传入参数元组绝对不能自己拼fINSERT ... {name}否则入住人姓名里带个单引号直接让 SQL 崩溃这是数据库课设最常见的低级错误二是cursor.lastrowid取刚插入客户的自增主键在事务提交前就能拿到三是conn.commit()和conn.rollback()的位置commit 必须放在所有 execute 完成之后。入住成功后手动调用房间列表和房间状态表格的refresh()界面状态才一致。4.4 退房结算跨天计费与事务回滚退房结算是课设里要算天数的地方也是调试最费时间的地方。一张 3 月 1 日入住、3 月 3 日退房的单子按小时算 48 小时是 2 晚按自然日算也是 2 晚看起来区别不大但如果客户 3 月 1 日晚上 11 点入住、3 月 2 日凌晨 1 点退房按 24 小时制不足一天就只收一晚按自然日则收两晚。酒店行业通行的口径是早于第二天中午 12 点退房不收当天费用。要在 Python 里把这件事做清楚不能用毫秒差值除 24那是按小时计费不是按酒店日卡计费。from datetime import datetime def calc_days(checkin_dt: datetime, checkout_dt: datetime) - int: ci checkin_dt.replace(hour0, minute0, second0, microsecond0) co checkout_dt.replace(hour0, minute0, second0, microsecond0) nights (co - ci).days if checkout_dt.hour 12: nights 1 return max(nights, 1)先把两个时间都归到零点再求 days得到的是“跨越了几次零点”然后判断退房时间是否超过中午 12 点超过说明白天空着也占用一天资源加收一晚。最后用max(nights, 1)兜底防止退房时间恰好等于入住时间时算出 0 元单。这里写错一个条件结账金额就会出现“住一晚收 0 元”的玄学 bug而且表面上看 SQL 一点问题都没有。退房结算服务端同样走事务读取 checkin 记录、算金额、写 checkout 表、把 room.status 改回 0、把 checkin.status 改为 0。任一步执行失败都必须回滚尤其要保证房间状态更新和 checkout 表写入的原子性。4.5 房间状态自动刷新QTimer 的加分项界面挂在那边不动数据库里房间被另一个客户端改了界面不会自己同步。写一个 QTimer每 30 秒调用一次load_room_table()属于成本极低但演示效果很好的功能from PyQt5.QtCore import QTimer self.timer QTimer(self) self.timer.timeout.connect(self.load_room_table) self.timer.start(30000)不要用while True: sleep(30)塞在主线程里那会直接冻结整个 GUIQTimer 是事件循环内部的异步机制不阻塞界面操作。窗口关闭时按常规习惯把 timer.stop() 放在 closeEvent 里避免程序退出时报一个 interrupted timer 的警告。5. 避坑与排查从安装报错到结账金额不对的 5 个典型现场5.1 现象PyQt5 安装失败pip 卡在某个依赖上具体报错有的是 “ERROR: Could not find a version that satisfies the requirement PyQt5”有的是在装 labelme 这类工具时因为它依赖 PyQt5 而连带安装失败。原因绝大多数是镜像源缺包、Python 版本过新或过旧、以及同时存在多个 Python 解释器导致 pip 指向错误。解决方式不要重复试官网源直接把镜像源写到用户配置里更省事pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install PyQt5 pymysql再用pip list | findstr PyQt5确认装上了。如果系统里同时装了 Anaconda 和官方 Python务必在项目里指定解释器比如 PyCharm 右下角选择解释器或者用python -m pip指定当前环境。5.2 现象运行时报 “error 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock”这个问题在 Windows 上表现为 “Cant connect to MySQL server on localhost (10061)”在 Linux 上表现为连 socket 文件失败。原因不是代码写错了而是 MySQL 服务根本没有启动或服务启动但监听端口不是 3306。解决分三步。第一步用netstat -ano | findstr 3306Windows或service mysql statusLinux确认端口监听第二步到 MySQL 安装目录的 my.ini 里确认port3306且bind-address127.0.0.1别让连接串里的 host 写成localhost而 MySQL 只监听 127.0.0.1 的独立地址第三步回到 dao.py 把 host 固定为127.0.0.1少走一层 DNS 解析和 socket 转换课设环境不需要考虑远程访问。5.3 现象中文乱码要么是问号池要么是空字符串检查顺序是“数据库 → 表 → 连接 → 界面”四级。数据库和表已经是 utf8mb4但 pymysql 连接串漏写了charsetutf8mb4写入的中文会变成 3 组乱码符号。另一个隐蔽点Windows 控制台本身是 GBK 编码如果在控制台直接打印查询结果utf8mb4 的中文也会显示乱码但这不代表库里的数据是坏的。先重启 MySQL 服务再在客户端里SELECT name FROM customer验证库内中文正常就说明问题只在连接层参数或控制台显示层。5.4 现象PyQt5 窗口里的汉字全部变成方块或者字体小得看不清原因不是中文乱码而是系统缺少能适配中文字符的字体映射PyQt5 默认字体在某些精简版 Windows 或 Linux 桌面环境里回退失败。解决方式是在 main.py 中强制指定字体font QFont(Microsoft YaHei, 10) app.setFont(font)Linux 上没有微软雅黑就指定 “WenQuanYi Zen Hei” 或 “Noto Sans CJK SC”。答辩用的机器如果只有默认中文字体建议把resize(1100, 780)改成固定尺寸并设置setMinimumSize避免窗口拉大后控件漂移。这个问题和业务逻辑无关但演示时界面全是方块老师对系统的第一印象直接崩盘。5.5 现象退房结算金额对不上特别是跨月和隔年订单常见的情况是入住 3 月 31 日退房 4 月 1 日手动推算应收 168 元程序算出 0 元。原因通常是用了(checkout_date - checkin_date).days直接求差如果入住时间和退房时间都是 DATETIME 且退房时间比入住时间早于 24 小时天数就是 0。解决方式是统一按 4.4 节的方法先归零再跨零点计算。另一个相关坑是跨年订单把DATEDIFF()写进 SQL 里计算时要注意 MySQL 的日期函数返回整数但遇到 2 月 29 日时窗口函数处理可能与 Python 不一致所以统一把日期计算放在 Python 层而 SQL 只负责取数。6. 让课设从“能跑”变成“能答辩”验证脚本、打包与加分项6.1 五分钟验收清单运行一段脚本走完全流程答辩前最怕的是演示到一半数据库连接断开。把下面这段验证逻辑写成test_smoke.py每次演示前跑一遍通过之后再开 GUIfrom dao import get_connection, query_available_rooms conn get_connection() assert query_available_rooms() is not None with conn.cursor() as c: c.execute(SELECT COUNT(*) AS cnt FROM room) row c.fetchone() assert row[cnt] 5, 房间初始化数据不完整 print(数据库连接与基础数据验证通过) conn.close()这段脚本能挡住 90% 的“数据库没问题却被误判为没连上”的尴尬。注意跑完记得 close 连接否则你会得到一堆 TIME_WAIT 状态的连接。6.2 把课设打包成 exe 的最小可行打包流程即使老师说“不用打包”做一个 exe 放在 U 盘里也是一种谈判优势。用 PyInstaller 打包命令如下python -m pip install pyinstaller python -m PyInstaller --noconfirm --windowed --name HotelMS app/main.py打包后把 db/hotel.sql 和 requirements.txt 复制到 exe 同目录的 docs 文件夹并在课设报告里写明“运行前需导入数据库脚本”。注意 PyInstaller 不会自动把.ui 文件塞进 exe如果代码里用uic.loadUi(ui_login.ui)动态加载就必须用--add-data ui_login.ui;.指定资源最省心的做法是把 .ui 文件提前用pyuic5转成 .py 再 import。6.3 报告里最容易拿分的三个细节数据和界面一一对应老师切换 Tab 时能看到房间表格的状态和入住登记页当前选中的房间一致这比任何吹牛都更有说服力。第二个加分项是把自己防“SQL 注入”的做法写进报告说明全部使用参数化查询并贴一段execute语句对比代码。第三个加分项是给表里的关键查询加上一条带索引的 SQL比如ALTER TABLE checkin ADD INDEX idx_room_status (room_id, status)报告里顺势写一句“通过对在住状态的组合查询建立索引演示查询时间从两位数毫秒降到一位数毫秒”。最后说一个我自己的习惯每次答辩前一晚都会把宿舍电脑上的 MySQL 服务停掉再启一次然后用验收脚本跑一遍全流程。GUI 编程类的课设栽跟头基本都是栽在“换了一台机器”上服务没起、端口被占、字符集没设三个小问题就能让整套系统从头翻到尾。提前交一份验证脚本到 U 盘里把能自动化的事交给代码现场就只剩讲方案这一件事项目自然稳稳落地。希望帮到你。本文还有配套的精品资源点击获取