C++控制台实现滚动字幕
这是大二的面向对象程序设计(C)这门课的期末大作业,老师的基本要求是:形成16*16汉字的字幕,并实现字体选择;有多种动画效果。
以下是我做完设计后提交的作业文档,对主要技术进行了详尽的解释:
字幕滚动思路流程与代码分析
预期效果
使用C++语言编写程序,在字符界面上模拟滚动字幕。
基本功能包括:
1.让用户输入汉字,然后在字符界面上实现16*16(每个汉字)的字幕。
2.具有三种不同的动画效果。
3.有10*9种背景颜色和字体颜色可供选择。
4.5种不同的字体可供选择。
4.界面友好,操作简便。
功能实现分析
对于这道“字幕显示”作业要求,我们遇到的第一个知识盲区就是如何将汉字用点阵的方式在控制台显示出来,甚至需要更改汉字的字体。博主“带她去流浪”(https://blog.twofei.com/embedded/hzk.html)为我们详细介绍了HZK库的用法和C++代码实现方式,这个问题迎刃而解!
步骤一:实现单字矩阵的显示
为便读者阅读,这里先附上博客内原文代码:
这里仍有两个地方需要解释:
- 汉字编码:GB2312编码方式使用两个字节(1字节区号、1字节位号)为一个汉字编码,计算:offset = (94*(区码-1)+(位码-1))*32得到汉字在HZK16库中的绝对偏移位置从而获取32个十六进制的数。
- 如何使用获得的编码:数组buffer[]和key[]做按位与运算,得到16*16矩阵每个点的信息,如下图:
解决了单字矩阵,多字如何同时显示呢?
步骤二:多字矩阵的显示
我们采用字符数组储存需要输出的字,并计算字符串长度:
(C++也可以使用string储存字符串,且有计算长度函数,但当时并没想到使用string,而是使用了字符数组,后来作业太多也没精力再进行尝试)
上述博客采取了printf(“ ”)实现矩阵多行显示,换行时自动出现在下一行第一列的位置。在已经打印了第一个字的基础上,要怎么让第二个字矩阵出现在第17~32列的位置呢(由于控制台不便使用像素为单位的坐标系,所以直接采取了以行和列为单位的坐标系定位)?我们采用了SetConsoleCursorPosition()函数来定义光标位置,这里以最简单的逐字输出为例:
其中,Y坐标只与字符行位置有关,X坐标与字符处于第几列、正在输出第几个字(CharNo)有关。SetConsoleCursorPosition()只对下一行代码修改坐标,因此事实上每一个符号都使用这个函数修改了坐标。
(有的组使用了一个大二维数组,比如16*160,先计算出要输出的字符在这个二维数组中的位置,再逐行输出整个二维数组,这个方法卡顿比我采用的方法小很多)
步骤三:设计动画显示
对于逐字显示、滚动出现、翻转出现三种动画,我们写了三个函数来分别完成单字的动画,然后在Play()函数中根据字符串长度决定调用动画函数次数。
这里需要说明的是,起初,为了使得时钟移动(TimeElapsed)前后打印的内容不冲突、输出的字不“拖尾”,我们在sleep()函数之后使用了system(“cls”)清屏函数,但是这个方法最大的缺点是屏幕闪烁情况严重,于是我们改用了另一个方法。我们用直接覆盖的方式解决了冲突问题,然后在屏幕空余的部分打印空格覆盖原来的字符,如下图:
基于上面逐字输出,滚动出现和翻转滚动的实现如下:
滚动出现:(核心部分)
解释:Width是屏幕显示滚动的列数,move随之时间变化字符的移动量,字符X坐标随move一直在减少,使用CycleTime = move / Width记录字符走过一个Width的次数,从而修正pos.X,使得字符实现在左边缘消失后在右边缘出现的效果。if (pos.X <= Width)语句表示在非显示区域的字符不打印,这一步主要是为了程序刚刚运行时字符不会溢出显示区域(因为该程序根本原理是在每一个Sleep()函数前都要完整打印一次16*16*字数矩阵和空白矩阵,不使用这个检验会导致程序刚运行时发生错乱),事实上CycleTime>0时并不需要这一检验步骤。
翻转滚动出现:(核心部分)
实现了滚动显示,实现矩阵翻转、镜像、缩放等功能实质只需要修改部分参数即可完成。
步骤四:菜单设计
菜单函数menu()的存在就是为了减少main()函数的代码,使得mian()函数看起来更加“清爽”。Menu()中包含四个选择函数,包括选择字体函数SelectType()、选择背景色函数SelectBGColor(),选择字体颜色函数SelectWordColor(),选择字体动画方式函数SelectShow()。其中大部分是使用了switch函数,根据用户输入的按键,返回一个string,最终传到play()函数中。下面是选择函数之一的代码:
总之,这是一个平平无奇的菜单小函数,main()函数将不停的调用它。它的存在是为了简化main()函数的代码,体现式布局更加美观。
不足和改进建议:
1.在不同的动画函数里面都包含了大量重复的代码,但是又有细微的不同。我们想改进方式也许可以将其中相同的部分抽象出一个类,用继承的方法来减少代码工作量。
2.网络上的大佬实现了鼠标点击操作菜单,但数次尝试均未成功,且在老师说控制台还是不要使用鼠标后成功劝退。我想控制台也许不适合鼠标,但应仍是可实现的(将控制台由行列坐标转换为像素坐标,获取鼠标位置),所以如有时间不妨一试。
本人小白,首篇博客试水,不妥之处请多指正鸭
相关文章
- 文章编写实用工具——Typora中常用的源码模式
- 文章编写实用工具——Typora中常用的语法与快捷键
- Gradle的使用——快速找到自己想要在gradle中使用的jar包
- Gradle的使用——dependencies的使用说明
- Gradle的使用——在windows上面安装gradle
- Gradle的使用——第一个构建脚本
- 开源项目——API接口管理平台建设v0.0.1立项(一)
- 用Go语言调用智能合约,做成Restful Api接口
- 开源项目——实现XSS过滤Cookie过滤拦截器(二)
- 开源项目 ——API接口管理平台数据库原型设计(三)
- Solidity开发的智能合约安全建议
- 统一认证鉴权协议错误导致服务器假死大量报504和502错误
- 个人博客建设——Hexo的一些常见组件设置
- 个人博客建设——Hexo的一些常见组件设置2
- 个人博客建设——Hexo主题icarus的_config.icarus.yml配置参数注释
- 流媒体工具部署与使用
- 个人博客建设——Hexo常用命令汇总
- 知识分享之Golang——函数的基本用法
- 知识分享之Golang——Bleve中的字符过滤器和分词规则
- 知识分享之Golang——Bleve中的Token filters各种标记过滤器