30天自制操作系统第11天

操作系统实验日志11

第11天:制作窗口

一、实验主要内容

1、 内容1:鼠标显示问题

以前鼠标移动到边界就不能再继续移动了,原因如下:

把鼠标左上角坐标的横坐标的范围限制在320-16,纵坐标的范围限制在200-16之中

在这里插入图片描述

所以我们可以讲鼠标左上角的坐标范围扩大到整个vram之内,但是这样会出现以下现象:

在这里插入图片描述

2、 内容2:实现画面外的支持

在上次实验修改后,鼠标的显示以及刷新放到了refresh函数中,所以需要修改该函数:

在这里插入图片描述

我最开始比较疑惑,就算空色框起来的部分加以限制了,但是传入的坐标在加上图层实际位置的坐标还是会超出范围啊,然后重新整体看了遍代码:

我们首先是在bootpack.c文件中的入口函数中先修正鼠标坐标,然后我们是调用的在这里插入图片描述语句,可以看到我们传入的是鼠标的实际坐标。是我把sheet_refresh函数搞混了,这个函数传入的是相对坐标。

除了这个,我还有一个误区就是,以为sheet_refreshsub函数的如下部分:

在这里插入图片描述

也是对画面外的部分进行修正,一看还真能有点像,但是其实不是的,这块只是对我们刷新的范围和对保存图层颜色的buf的范围的一个比较。

现在问题解决:

在这里插入图片描述

3、 内容3: shtctl的指定省略

很多函数的参数都有一个struct SHTCTL *ctl,作者感觉没必要,他就在结构体SHEET中加入了struct SHTCTL *ctl,也就是该结构体的实际存在的首地址,这样传参的时候就只传struct SHEET *就可以了。

这样子就需要对SHTCTL结构体的初始化函数进行修改:

在这里插入图片描述

剩下的函数修改就只讲对应的ctl参数去掉就行了。

4、 内容4:显示窗口

制作一个位置固定的窗口,其height应该在鼠标和背景图之间:

在这里插入图片描述
在这里插入图片描述

对入口函数进行修改:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5、 内容5:小实验

将鼠标和窗口的height值换一下:

在这里插入图片描述

可以看到鼠标在窗口得下一层:

在这里插入图片描述

6、 内容6:高速计数器

设计一个可以在窗口内计数得功能,只需要修改入口函数:

前面主要是将窗口变小了,主要修改得部分在无限for循环中:

在这里插入图片描述

运行结果:

在这里插入图片描述

可以看到,画面在不停的闪烁,原因是刷新的时候是先刷新背景区域,再刷新的窗口图层的区域。

7、 内容7:消除闪烁1

我们每次刷新是将指定区域内的所有图层全部进行刷新,其实如果下层的图层不发生变化那么就无需使其变动,我们只需要刷新发生变动的图层及其上面的图层(因为如果不刷新height值高于它的图层那么它的上层就会被它覆盖):

更改后我们需要时刻考虑,对于不同的变动我们的参数值应该使用什么!

①修改sheet_refreshsub函数:
在这里插入图片描述

②修改调用了sheet_refreshsub函数的sheet_refresh函数进行修改:

在这里插入图片描述

③修改sheet_slide函数:

在这里插入图片描述

*对于图层移动之前的那部分区域,图层移动之后,位于该图层下面的图层可能原来是被盖住的现在可能要重新露出来,而我们也不知道被该图层盖住了几个图层,所以我们要从最底层开始刷新。
   对于图层移动后的部分,因为图层的height值是没有变化的,所以对于height值小于该图层的图层盖住就盖住了,所以只刷新该图层以及该图层之上的图层就可以了。*

④修改sheet_updown函数:

在这里插入图片描述
在这里插入图片描述

运行结果:

在这里插入图片描述

修改后,就只刷新窗口图层还有鼠标,所以说窗口不会有绿色的背景闪现,但是鼠标还是一闪一闪的。

8、 内容8:消除闪烁2

要避免闪烁,就要在写入的过程中不对鼠标所在的vram的位置进行写入,这里引入了一个map,大小和vram相同,用来记录那些像素都属于哪些图层。

在这里插入图片描述

①对map变量进行声明以及初始化
在这里插入图片描述

在这里插入图片描述

②绘制map区域

在这里插入图片描述

疑问:为什么sid不直接使用height不是更方便吗

③改写sheet_refreshsub函数,使其可以使用map

对照map来刷新vram的话,就只刷新被修改的图层就可以了,所以通过参数h0和h1来指定被刷新的图层。

在这里插入图片描述

④修改调用sheet_refreshsub函数的sheet_refresh函数:

因为该函数不改变上下层关系、不对图层做移动和变换,所以无需重写map

在这里插入图片描述

⑤修改调用sheet_refreshsub函数的sheet_slide函数:

因为图层要移动,所以涉及了对map的重写。在该函数中,首先重写map,分别对应移动前后的图层,然后调用sheet_refreshsub函数。在移动前的地方,只针对上层图层移走之后而露出的下层图层进行重绘就可以了。在移动目的地处重绘了一张移动走过去的图层。

在这里插入图片描述

⑥修改调用sheet_refreshsub函数的updown函数:

在这里插入图片描述
在这里插入图片描述

当所有的函数都修改成功后,再运行就没什么问题了.

二、问题(在上面的内容也有详细的解释)

1、 添加一个窗口图层有哪些步骤?(格式:文字说明+对应代码)

(1) 制作绘制窗口的函数,即对窗口大小、像素值等的初始化;

在这里插入图片描述

(2) 定义图层包(结构体SHTCTL),建立图层(SHEET),建立缓冲区buf(地址)

在这里插入图片描述

(3) 初始化图层

在这里插入图片描述

(4) 为窗口图层分配内存,窗口大小为160*52

在这里插入图片描述

(5) 设置窗口图层的缓冲区大小和透明色

在这里插入图片描述

(6) 调用窗口函数和显示函数,给窗口定义初始首坐标
在这里插入图片描述

(7)设置可上下左右移动窗口图层函数,即设置图层显示位置的起始坐标

在这里插入图片描述

(8)设置窗口图层高度

在这里插入图片描述

2、 教材202页,为什么鼠标移动到最右边后左边会出现鼠标图案?

鼠标移动有两步:对原位置进行刷新、对新位置刷新。

在刚开始的时候作者为了让操作系统更加符合实际,能够让鼠标从边界出去,所以改动了鼠标移动的边界,使鼠标可以在右边隐藏起来。通过这个代码实现的
在这里插入图片描述

但是之前为了显示鼠标图层,sheet_refreshsub函数会把图层内容写入到VRAM中,因此,即使鼠标图层的一部分处在了画面之外,函数依然会刷新图层,包括画面以外的部分,但在右边已经没法写入到VRAM中,函数会自动将画面外的图层部分写入到左边所对应的VRAM中。所以鼠标移动最右边后,左边会出现鼠标图案,但在画面中的部分在每次移动之后都会刷新。按照上面这个代码的修改,会导致刷新的像素点往后偏移16位(相当于往右),所以在屏幕左边会出现鼠标。对刷新图层来说,传入的参数vx0=mx和vx1>xsize,对新图层来说,也是vx0=mx和vx1>xize,而且老图层和新图层的vx1值是相同的,因为当我们把鼠标放到最右边的时候,传入的mx都是同一个值,所以计算出的vx1也是同一个值(mx+16),这个时候两次调用的bx1相同,会先刷新一次老的,再刷新一次新的,那还是在原来的位置,所以鼠标只能在左边的固定范围内出现。

3、 教材216页,每个图层的sid是如何设置的?具体数值等于多少?举例说明,建议编程打印sid进行验证。

用图层结构体数组对应标号元素的首地址减去图层结构体数组的首地址(跟图层高度根本没有关系)。实际上sid是一个地址,是sheet ID的缩写。

每个sheet_alloc放一个图层信息进来占据一个结构体数组(假设每个元素的大小为3字节,再假设结构体体数组首地址为0X00。)。放了一个,那么第0个元素首地址就是结构体数组的首地址,这时sid=0; sheet_alloc第二个图层进来,就是第一个元素,首地址0X03,sid=0X03-0X00=3;依次类推,根据图层sheet_alloc进来的顺序,依次是0、3、6、9……。所以sid的大小只和图层sheet_alloc的顺序和sheets0元素的大小有关,和图层高度没有关系。

4、 教材216-217页,结合代码,解释刷新函数(sheet_refreshsub)的参数和实现逻辑。

在这里插入图片描述
在这里插入图片描述

5、 教材217页,结合代码,解释滑动函数(sheet_slide)的参数和实现逻辑,注意内部调用sheet_refreshmap和sheet_refreshsub时的传参,特别是高度参数,为什么这样传。

这样传的原因是,只绘制了中间变化的图层,而不需要重新绘制鼠标图层,消除了鼠标因为自身不停的被覆盖再绘制所产生的闪烁。

在这里插入图片描述

三、程序设计创新点

除了窗口的扩大、缩小、关闭、拖动,还实现的创新为:

1、描述创新点1:实现鼠标双击功能

在这里插入图片描述

2、描述创新点2:和windows一样,当鼠标移动到右上角的3个图标,图标颜色加深。

在这里插入图片描述

效果图:

在这里插入图片描述

3、创新3:可以自由拖动窗口大小

在这里插入图片描述
在这里插入图片描述

四、实验心得体会

这次实验做的事情不多,就是先对以前的代码完善了一下之后,又新建了一个窗口图层,然后又实现了在这个窗口图层上显示文字、计数,然后又解决了因为刷新带来的闪烁问题。解决闪烁问题的时候最开始就是对需要刷新的图层的数目做了适当的减少,然后又引入了一个map,这样刷新的时候就可以只刷新属于该图层的露出来的部分,这样还顺便使代码的执行效率增强了。一点一点跟着作者的思路感觉并不难,但是当我想要回过头一点一点想清楚整套代码的架构时,感觉好多内容都被忘记了,所以做好笔记还是蛮重要的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值