前言
众所周知,期末考试周结束后,迎来的不是荒淫放荡的暑假生活,而是依旧忙碌的小学期。
小学期的第一周,全是高级语言设计课。说是上课,其实除了第一天讲了一天的软件工程之外,剩下四天全都是搬着笔记本待在教室里敲代码。为了提供笔记本的电源,助教还得向物业借许多排插。不是很明白为什么非得在教室敲,只要作业完成了在哪里其实都一样吧。
题目有两个,我的题目是模拟地铁自动售票系统,另一个是职工档案管理系统。第二个有点像是大一上C语言实验课做的学生成绩管理系统,不过要比那个多很多功能。两个题目都需要做用户交互界面。
我选到第一个还是比较幸运的,因为第一个核心代码并不是特别的多,主要程序还是在界面设计上,至少对我来说是这样的。而第二个题目之前也做过类似的,感觉并不能学到什么比较新的东西。
这一周感觉大部分时间都在各种乱七八糟的事情上折腾,像是安装图形库,配置sublime,设计交互界面之类的,作业一拖再拖,直到第一周周日才做好。第二周又马上要开始认知实习课程,前四天一天到晚就要往外跑,参观各种企业。加上社团的项目,robomaster的选拔培训,之类的,实验报告到周四才完成。到周五认知实习答辩结束,原以为可以休息一阵子,谁想突然又说这门课也要答辩,报告也需要修改。周末写了几篇博文,再把PPT做好,就过去了。报告是懒得改了……原先是这么想的,结果呢,终究还是逃不过去,答辩结束后还是要修改。好在这次比起之前要求修改多了一些要求,好下手。
说真的,每每想到这门课只有一个学分,而且还不是考察课,我总有一种随便做做就算了的想法。这一而再再而三的要求也着实令人厌烦,只想快点结束。若不是真的学到了一些东西,我必定不会写这篇博文。时到如今,多说也无益了。
任务概述
设计一个具有购买车票、地图查询、系统说明、退出等功能的模拟地铁自动售票的系统。
系统要求具有欢迎界面,界面显示作者信息和版权信息。进入系统主菜单后提供购票选项、地图查询选项、系统说明、退出系统四个选项。
系统说明界面详细的介绍了购票流程,并且附有用户须知。
购票系统实现通过键盘输入起止站和票价,并且以此计算阶梯票价。根据系统提示进入投币找币流程,购票成功后返回欢迎界面。
查询系统通过输入站台编号查询站台信息。查询成功后可选择继续查询、购票或是返回。
运行环境
操作系统:Windows7
开发环境:codeblocks+EGE图形库
系统设计
总体架构设计
整个系统分为地图查询系统和购买车票系统。
由于代码比较多,我将其分写到mian.cpp、map.cpp、data.cpp、sold.cpp、Welcome.cpp、Index.cpp、description.cpp共七个cpp文件中。然后新建了一个名为”kxj.h”的头文件,在里面声明多个文件共用的函数,结构体以及外部变量。
其中每个文件的作用如下:
Welcome.cpp:绘制欢迎界面。
Index.cpp:绘制系统主菜单界面。
description.cpp:绘制系统说明界面。
data.cpp:地铁信息初始化。
Map.cpp:绘制地图查询界面,以及实现查询地图的功能。
Sold.cpp:绘制购买车票界面,以及实现输入起止站和车票数与投币功能。
Main.cpp:调用各个功能以及界面,并提供主界面的按钮点击功能。
模块分析与设计
头文件
公用函数分析
1
2
3
4
5
6
7
8
9void DrawOpt(int x,int y,int w,int h,int fnum,int fh,char optTitle[]);//绘制按钮键。
void Title();//标题
void Copyright();//版权信息,每一页的标配
bool checkClick(int *x,int *y);//检测是否有点击,并且获取点击的位置
void Init();//初始化页面,使之清空,并且有标题与版权信息
void textBox(int x,int y,int w,int h,int r);//绘制输入框
int Input(int x,int y,int n,int fh,int (*click)(int x,int y));//在某输入框内输入。每次循环同时检测鼠标消息与键盘消息,确保键盘与鼠标都能够实现所需效果。
void Delete(int x,int y,int w,int h);//使某一矩形变成背景色,实现删除效果
bool checkIn(int mx,int my,int x,int y,int w,int h);//检测点击位置是否在某处结构体STA是站台信息的存储类型,数组下标就是编号
1
2
3
4
5
6struct STA{
string name;//站点名称
int line;//站点路线
string pre;//上一站名称
string nxt;//下一站名称
};
地铁信息初始化
通过循环将站台信息整合到结构体STA数组中,数组下标即为编号。换乘点拥有多个编号,不同线路上编号不同。
将八条线路图建成无向连通图。其中每一个编号视为一个点。一条线路上相邻两站之间连通,距离直接打表写入文件。换乘点不同编号之间距离为零。不连通的点之间距离为oo(1000000007)。
1 | void Query_same(int x){ |
欢迎界面,系统主菜单以及系统说明界面
通过EGE图形库的库函数设计。
官方文档
地图查询系统
通过EGE图形库中的库函数完成交互界面。
查询站台时,先检测所查询编号是否合理,然后通过暴力查询,遍历每个站台,寻找所有站台名称相等的元素,加入到Line数组中,最后输出。
查询的代码如下:
1 | void Query(int num){ |
购买车票系统
通过EGE库函数完成交互界面,实现输入功能。
计算阶梯票价时,先用无优化的最短路径dijstra算法计算出两者间的最短路径,然后将路径向上取整,根据规则计算出单价。
计算票价的代码如下:
1 | void calcLine(){//dijkstra计算最短路 |
系统主菜单
初始化窗口。
用EGE的库函数完成交互功能。点击“地图查询”“购买车票”“系统说明”直接调用相关函数。点击“退出系统”时则退出循环。
1 | int main(){ |
软件结构(流程图)
调试过程
我首先编写完系统的核心代码,如地图查询与购买车票。这一块没有遇到太大的问题。改正几处简单的错误之后,便通过了测试。
接下来我开始绘制图形界面。按钮、输入框、文字等只需要稍微计算一下便能够符合我的预期。
较为困难的是用户交互机制的设计。我先是设计键盘交互的部分,这一块较为简单。也没有需要调试的地方。但是当我加入鼠标交互功能是,却遇到了难题:当用户输入的时候,无法通过鼠标点击相应按钮实现功能。必须等到输入结束之后才能实现鼠标点击。而且需要鼠标点击的阶段也无法通过键盘操作。即无法同时用鼠标和键盘进行操作。
为了解决这一问题,我在需要用户操作的阶段设置了一个while(1)循环,里面先检测是否有键盘消息,如果没有再检测是否有鼠标消息。通过这样类似于多线程的方法,系统可以实现同时通过鼠标和键盘操作,代码如下:
1 | while(1){ |
但是此时又造成了另一个问题——页面无法及时的更新。在之前的代码中,程序只有到getch(),即等待用户按键的时候,才会更新页面。原先因为只有键盘输入所以不会造成影响。而如今只有检测到键盘消息,才读取键盘操作,导致页面无法及时更新。思考片刻后,我认为系统只有等待的时候才会更新界面,所以我在每一处改变页面的代码之后加了delay_fps(60)
延时函数。正如我猜想,加入延时函数之后,问题成功解决。
测试结果
- 进入系统后,显示欢迎界面:
- 按任意键进入系统主菜单,点击对应按钮进入对应的功能界面。
- 进入购买车票的界面后,出现起止站的输入框。首先通过键盘输入起始站,将在输入框中出现相应字符。最多输入3个字符,而且必须是数字。点击确定或者按下回车键后,可以在目的地的输入框中输入。点击刷新按钮后可以从起始站重新输入。点击返回或者按下esc键将回到主界面。起止站输入完成后,点击确定键或者回车键,如果站台编号符合要求将进入输入票数的界面。若是不符合将被要求重新输入站台编号。
- 输入票数的界面中,标题下方显示两个站点之间最短距离的票价。再下面是询问购买的票数,可通过键盘输入数字字符,最多可输入一个字符。点击返回或者按下esc键回到上一界面。点击确定或者按下回车键进入下一界面。
- 显示总价格,并且最后询问是否购买车票。点击返回或者按下esc键回到上一界面。点击确定或者按下回车键进入下一界面。
- 投币界面中标题下方出现提示。按数字键可以在界面右下方的输入框中输入数字字符,最多可输入两个字符。点击确定或者回车键,如果投入的钱币小于总价格,则显示“钱币不足,请再次投币”。直到投入钱币总和大于等于总价格,到下一界面。
- 购买成功后,显示信息与提示,按任意键返回主界面。
- 进入地图查询界面后,显示地铁线路图,并且在线路图下方有输入框,可以输入站点编号。只能输入数字,且最多三个字符。点击查询可以在线路图右侧显示查询的地图信息。在屏幕右下方出现“继续查询”与“购票”按钮。点击“继续查询”,可以继续输入站点编码。点击“购票”按钮直接进入购票界面。点击返回或者按下esc键返回系统主界面。
- 系统说明界面显示购票流程与用户须知,按任意键返回系统主界面。
问题
- 无法输入中文字符。EGE自带的键盘输入字符函数是直接从读取按下的键盘按键,所以无法从输入法输入中文。唯一的解决方法是通inputbox_getline()函数,用对话框让用户输入一个字符串。但是因为对话框样式风格与系统界面不符,也没有找到改变对话框样式的方法,所以没有通过输入站台名称查询站台信息的功能。
- 没能清空鼠标缓存消息。不过好在这一点因为点击之后能够马上切换到新的界面,所以没有构成什么问题。
可提升空间
- 当鼠标移到或点击按钮时,出现动画。
- 输入站名查询站点信息。
- 提供点击站点即可查询信息的功能。
分析总结与心得体会
本次程序设计,不仅让我复习巩固了许久未用的最短路径算法,并且让我熟悉了使用库函数设计用户交互界面。而且将代码写在不同文件中,自己写一个头文件也是第一次尝试。虽然在新事物上折腾了很多时间,但结果还是非常令人满意的。经过此次课程,我的确获得了极大的进步。