7 消除闪烁(1)(harib08g)

窗口图层刷新是因为窗口的内容有变化,所以要在画面上显示变化后的新内容。基本上来讲,可以认为其他图层的内容没有变化(如果其他图层的内容也变了,那么应该会随后执行该图层的刷新)。

既然如此,图层内容没有变化也进行刷新的话就太浪费了。如果只是窗口变了,那背景就不用刷新了。另外,假如上面有鼠标,但鼠标的图层没有变化,那我们应该刷新吗?必须要刷新。窗口的刷新,可能会覆盖鼠标的一部分显示区域。

综上所述,仅对refresh对象及其以上的图层进行刷新就可以了。那么我们赶紧按照这个思路修改程序吧。

■■■■■

首先修改为我们完成刷新工作的sheet_refreshsub函数。

本次的sheet.c节选

  1. void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0)
  2. {
  3. (中略)
  4. for (h = h0; h <= ctl->top; h++) {
  5. (中略)
  6. }
  7. return;
  8. }

我们追加了h0参数,只对在此参数以上的图层进行刷新。然后还要把所有调用了sheet_refreshsub的函数都修改一下。

本次的sheet.c节选

  1. void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1)
  2. {
  3. if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新 */
  4. sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1,
  5. sht->height);
  6. /* ↑这里! */
  7. }
  8. return;
  9. }
  10. void sheet_slide(struct SHEET *sht, int vx0, int vy0)
  11. {
  12. int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
  13. sht->vx0 = vx0;
  14. sht->vy0 = vy0;
  15. if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新*/
  16. sheet_refreshsub(sht->ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
  17. sheet_refreshsub(sht->ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height);
  18. /* ↑这里! */
  19. }
  20. return;
  21. }
  22. void sheet_updown(struct SHEET *sht, int height)
  23. {
  24. (中略)
  25. /* 以下主要是对sheets[]的重新排列 */
  26. if (old > height) { /* 比以前低 */
  27. if (height >= 0) {
  28. /* 中间的提起 */
  29. for (h = old; h > height; h--) {
  30. ctl->sheets[h] = ctl->sheets[h - 1];
  31. ctl->sheets[h]->height = h;
  32. }
  33. ctl->sheets[height] = sht;
  34. /* 这里 */ sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1);
  35. } else { /* 隐藏 */
  36. if (ctl->top > old) {
  37. /* 把上面的降下来 */
  38. for (h = old; h < ctl->top; h++) {
  39. ctl->sheets[h] = ctl->sheets[h + 1];
  40. ctl->sheets[h]->height = h;
  41. }
  42. }
  43. ctl->top--; /* 正在显示的图层减少了一个,故最上面的高度也减少 */
  44. /* 这里 */ sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0);
  45. }
  46. } else if (old < height) { /* 比以前高 */
  47. if (old >= 0) {
  48. /* 中间的图层往下降一层 */
  49. for (h = old; h < height; h++) {
  50. ctl->sheets[h] = ctl->sheets[h + 1];
  51. ctl->sheets[h]->height = h;
  52. }
  53. ctl->sheets[height] = sht;
  54. } else { /* 从隐藏状态变为显示状态 */
  55. /* 把在上面的图层往上提高一层 */
  56. for (h = ctl->top; h >= height; h--) {
  57. ctl->sheets[h + 1] = ctl->sheets[h];
  58. ctl->sheets[h + 1]->height = h + 1;
  59. }
  60. ctl->sheets[height] = sht;
  61. ctl->top++; /* 显示中的图层增加了一个,故最上面的高度也增加 */
  62. }
  63. sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height);
  64. /* ↑这里 */
  65. }
  66. return;
  67. }

修改的内容很少,我们逐一来看一下。对于sheet_refresh函数,我们按照刚才的思路让它只刷新指定的图层和它上面的图层。

在sheet_slide函数里,图层的移动有时会导致下面的图层露出,所以要从最下面开始刷新。另一方面,在移动目标处,比新移来的图层位置还要低的图层没有什么变化,而且只是隐藏起来了,所以只要刷新移动的图层和它上面的图层就可以了。

在sheet_updown函数里,按照同样的思路,针对个别不需要自下而上全部刷新的部分只进行局部刷新。这样修改以后,闪烁现象应该就会消失了。

■■■■■

完成了,我们来“make run”看看。

7 消除闪烁(1)(harib08g) - 图1

闪烁现象消失了

不错,性能越来越完善了。哎?等等,怎么稍微一动,鼠标就又出问题了!

7 消除闪烁(1)(harib08g) - 图2

鼠标变得一闪一闪的

数字部分的背景闪烁问题是解决了,可是把鼠标放在上面时,鼠标又闪烁起来了(不过,从截图看不出来)。嗯,这可是个问题。