7 消除闪烁(1)(harib08g)
窗口图层刷新是因为窗口的内容有变化,所以要在画面上显示变化后的新内容。基本上来讲,可以认为其他图层的内容没有变化(如果其他图层的内容也变了,那么应该会随后执行该图层的刷新)。
既然如此,图层内容没有变化也进行刷新的话就太浪费了。如果只是窗口变了,那背景就不用刷新了。另外,假如上面有鼠标,但鼠标的图层没有变化,那我们应该刷新吗?必须要刷新。窗口的刷新,可能会覆盖鼠标的一部分显示区域。
综上所述,仅对refresh对象及其以上的图层进行刷新就可以了。那么我们赶紧按照这个思路修改程序吧。
■■■■■
首先修改为我们完成刷新工作的sheet_refreshsub函数。
本次的sheet.c节选
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0)
{
(中略)
for (h = h0; h <= ctl->top; h++) {
(中略)
}
return;
}
我们追加了h0参数,只对在此参数以上的图层进行刷新。然后还要把所有调用了sheet_refreshsub的函数都修改一下。
本次的sheet.c节选
void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1)
{
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新 */
sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1,
sht->height);
/* ↑这里! */
}
return;
}
void sheet_slide(struct SHEET *sht, int vx0, int vy0)
{
int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
sht->vx0 = vx0;
sht->vy0 = vy0;
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新*/
sheet_refreshsub(sht->ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
sheet_refreshsub(sht->ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height);
/* ↑这里! */
}
return;
}
void sheet_updown(struct SHEET *sht, int height)
{
(中略)
/* 以下主要是对sheets[]的重新排列 */
if (old > height) { /* 比以前低 */
if (height >= 0) {
/* 中间的提起 */
for (h = old; h > height; h--) {
ctl->sheets[h] = ctl->sheets[h - 1];
ctl->sheets[h]->height = h;
}
ctl->sheets[height] = sht;
/* 这里 */ sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1);
} else { /* 隐藏 */
if (ctl->top > old) {
/* 把上面的降下来 */
for (h = old; h < ctl->top; h++) {
ctl->sheets[h] = ctl->sheets[h + 1];
ctl->sheets[h]->height = h;
}
}
ctl->top--; /* 正在显示的图层减少了一个,故最上面的高度也减少 */
/* 这里 */ sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0);
}
} else if (old < height) { /* 比以前高 */
if (old >= 0) {
/* 中间的图层往下降一层 */
for (h = old; h < height; h++) {
ctl->sheets[h] = ctl->sheets[h + 1];
ctl->sheets[h]->height = h;
}
ctl->sheets[height] = sht;
} else { /* 从隐藏状态变为显示状态 */
/* 把在上面的图层往上提高一层 */
for (h = ctl->top; h >= height; h--) {
ctl->sheets[h + 1] = ctl->sheets[h];
ctl->sheets[h + 1]->height = h + 1;
}
ctl->sheets[height] = sht;
ctl->top++; /* 显示中的图层增加了一个,故最上面的高度也增加 */
}
sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height);
/* ↑这里 */
}
return;
}
修改的内容很少,我们逐一来看一下。对于sheet_refresh函数,我们按照刚才的思路让它只刷新指定的图层和它上面的图层。
在sheet_slide函数里,图层的移动有时会导致下面的图层露出,所以要从最下面开始刷新。另一方面,在移动目标处,比新移来的图层位置还要低的图层没有什么变化,而且只是隐藏起来了,所以只要刷新移动的图层和它上面的图层就可以了。
在sheet_updown函数里,按照同样的思路,针对个别不需要自下而上全部刷新的部分只进行局部刷新。这样修改以后,闪烁现象应该就会消失了。
■■■■■
完成了,我们来“make run”看看。
闪烁现象消失了
不错,性能越来越完善了。哎?等等,怎么稍微一动,鼠标就又出问题了!
鼠标变得一闪一闪的
数字部分的背景闪烁问题是解决了,可是把鼠标放在上面时,鼠标又闪烁起来了(不过,从截图看不出来)。嗯,这可是个问题。