目录
-
题目
- 题目分析
- 思路解析
- 知识点涉及
- 代码展示
-
优化思考
- 问题一:观察界面切换效果,可明显观察到界面切换时有明显的刷新效果,有点影响使用效果
- 问题二:图片的按键位置不能相近或者重合,否则有误触导致执行了别的功能
- 问题三:当快速来回点击触摸屏两个位置时,会出现点击位置坐标读取与实际触摸坐标不一致的情况
题目
设计一个程序,该程序在运行之后自动播放一段开机动画,开机动画结束后可以调转到登录界面,登录界面有2个按钮,分别是登录和退出,点击登录之后可以显示系统主界面。主界面自拟,要求主界面有一个返回按钮,点击返回按钮可以回到登录界面。要求:不可以使用 goto 语句。
题目分析
该题目的主要诉求可总结为:
- 开机时需要有一段开机动画,且在开机动画结束后可以之间到达操作主界面
- 主界面上会有两个按钮,即切换界面和退出
- 界面切换不能使用goto语句
思路解析
- 开机动画可以使用裁剪工具GIFtiqu将动态图裁剪为一张张jpeg图片,在将jpeg图片解码循环显示,且可以将登录界面图片放至循环的最后一张。
- 触屏按键切换,该功能涉及到读取LCD屏的触摸屏设备信息。需要创建对应格式的结构体变量,并利用read()函数将设备文件中的信息存储进创建的结构体变量中。
- 由于读取触摸屏参数不能只读一次,所以采取死循环作为循环,并设置退出键坐标为退出循环或者退出整个程序。
知识点涉及
- 开机动画图片循环时,需要使用usleep()控制循环间隙。该函数的单位为微秒,且1s(秒) = 1000ms(毫秒),1ms(毫秒) = 1000μs(微秒)。经过计算,使得图片循环能够满足人眼视觉残留条件,最终达到图片“动”起来的效果。
- 由于开机动画使用的是JPEG图片,所以还涉及到JPEG的解码步骤。
- 触摸屏的设备信息在linux系统下也是一个文件,所以我们可以通过read()将这些信息读取到特定结构的结构体变量中,再来对获取到的参数做相应的操作。
代码展示
/*******************************************************************
*
* file name: main.c
* author : 790557054@qq.com
* date : 2024/05/14
* function : 该案例是掌握LCD屏触摸原理以及显示图片切换过程
* note : None
*
* CopyRight (c) 2023-2024 790557054@qq.com All Right Reseverd
*
* *****************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include "jpeglib.h"
/********************************************************************
*
* name : read_JPEG_file
* function : 实现完成libjpeg库的移植,实现在LCD上的任意位置
显示一张任意大小的jpg图片,并且对可能越界的情况做错误处理。
* argument :
* @filename :需要解码的jpg图片
@start_x :图片显示初始位置的横坐标
@start_y :图片显示初始位置的纵坐标
@lcd_mp :LCD屏内存映射空间的地址
*
* retval : 调用成功返回1,调用失败返回0
* author : 790557054@qq.com
* date : 2024/05/13
* note : 学习JPEG的解码过程,以及JPEG存储颜色分量的方式
*
* *****************************************************************/
int read_JPEG_file(char *filename, int start_x, int start_y, int *lcd_mp)
{
/*[1]:创建解码对象,并且对解码对象进行初始化,另外需要创建错误处理对象,并和解码对象进行关联*/
// 创建解码对象,其是一个结构体变量
struct jpeg_decompress_struct cinfo;
// 创建错误处理对象
struct jpeg_error_mgr jerr;
// 将错误处理对象与解码对象相关联
cinfo.err = jpeg_std_error(&jerr);
// 对解码对象进行初始化
jpeg_create_decompress(&cinfo);
/*[2]:打开待解码的jpg图片,使用fopen的时候需要添加选项”b”,以二进制方式打开文件!*/
FILE *infile; // 接收打开文件的文件指针
unsigned char *buffer; // 输出行缓冲区
int row_stride; // buffer一行的像素点数量,即图片的宽度
// 以二进制方式打开图片,并进行错误处理
if ((infile = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %sn", filename);
return 0;
}
// 把打开的文件的文件指针和解码对象进行绑定
jpeg_stdio_src(&cinfo, infile);
/*[3]:读取待解码图片的文件头,并把图像信息和解码对象进行关联,通过解码对象对jpg图片进行解码*/
(void)jpeg_read_header(&cinfo, TRUE);
/*[4]:可以选择设置解码参数,如果打算以默认参数对jpg图片进行解码,则可以省略该步骤!*/
/* 在该习题要求中,并不涉及图片缩放等问题,所以我们可以省略该步骤
* jpeg_read_header(),
*/
/*[5]:开始对jpg图片进行解码,调用函数之后开始解码,可以得到图像宽、图像高等信息!*/
// 我们只需要调用该函数,将图像信息放入解码对象中,无需注意其的返回值
(void)jpeg_start_decompress(&cinfo);
/*[6]:开始设计一个循环,在循环中每次读取1行的图像数据,并写入到LCD中*/
// 计算图像一行的大小
row_stride = cinfo.output_width * cinfo.output_components;
// 为自定义缓冲区申请堆内存,注意申请的内存空间大小应为图像一行的大小
buffer = calloc(1, row_stride);
// 定义一个int类型变量,用于存放颜色分量数据
int data = 0;
/*定义一个循环,用于循环写入一行的图像数据;
使用解码对象当前扫描行数与图像的高比较结果作为循环条件,当两者相等,即图像数据写入完后退出循环*/
while (cinfo.output_scanline = 2)
{
printf("x = %dt", x); // 输出X轴坐标
printf("y = %dn", y); // 输出Y轴坐标
cnt = 0;
}
}
// 6.实时判断读取到的触摸屏坐标,施行相应的功能
// 登录界面
if (x >= 336 && x = 396 && y = 646 && x = 33 && y = 628 && x = 397 && y
优化思考
问题一:观察界面切换效果,可明显观察到界面切换时有明显的刷新效果,有点影响使用效果
分析:
初步分析是因为JPEG解码后,是通过一行一行像素点写入LCD映射空间的,故而导致可以看到明显的从上到下的切换效果。
优化方向:
- 优化JPEG解码步骤的循环:使得图片可以更快更好的写入进LCD映射空间内,但是这个方向实现起来较为麻烦。
- 将界面切换过程均换成动态图:经过观察开机动画,发现过程中完全看不到刷新效果,可以达到丝滑切换图片的效果,所以初步设想是因为图片切换速度超过人眼观察速度,所以我认为这个方向可以实现。且考虑到切换界面动画的框架可以保持一致,这样省去了大量的准备步骤,还能够获得更好的效果,准备在项目内试验。
问题二:图片的按键位置不能相近或者重合,否则有误触导致执行了别的功能
分析:
这是因为当前程序的架构,是将读取屏幕触屏参数与条件判断直接放在一起循环导致的。read()函数会像scanf()函数那样有等待的过程,所以当用户没有触摸时,程序会卡在read()处。
优化方向:
- 对程序进行模块化编程:这样可以将各个界面的读取参数与判断间隔开,降低各个界面之间的耦合性。即在这个界面函数结束前,只会进行该界面的按键位置条件判断,从而消除误触执行其他功能的可能性。
问题三:当快速来回点击触摸屏两个位置时,会出现点击位置坐标读取与实际触摸坐标不一致的情况
分析:
初步分析是因为读取触摸坐标的机制导致的,但是目前没有办法证实,期待后续的学习。
优化方向:
-
满足一次条件判断后,将存储获取参数的变量清空:经过实测发现,只要在满足条件判断后,将变量内参数情况,再进行读取赋值操作,便可以丝滑进行界面切换,不会出现读取坐标与实际触摸坐标不同的情况。
同样,原理未知,期待后续学习补充。