ucGUI重绘分析(三)

本文深入探讨μc/GUI的重绘机制,包括重绘函数的作用、无效窗口的形成原因、设置无效区域的方法以及如何判断和设置无效窗口。通过详细分析,帮助读者理解μc/GUI在不同场景下如何高效地进行窗口重绘。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进行重绘的几个函数

在μc/GUI 中有三个具有进行重绘功能的函数——WM_Paint();、 WM_Exec();和
GUI_Exec();函数。
WM_Paint();函数用于立即重绘某一个窗口,而不用等到系统调用 WM_Exec();遍历无
效窗口时的重绘,其使用如下:
……
WM_Paint(hWin);//在此处立刻重绘窗口 hWin
……
WM_Exec();和 GUI_Exec();函数两者的区别是 GUI_Exec();是添加了时间功能的重绘
函数,它不仅调用 WM_Exec();进行图形界面对触摸屏、按键、重绘的相关处理,还调用
GUI_TIMER_Exec();函数遍历所有的定时触发器 TIMER, 处理那些达到定时时限的定时触
发器。

 

这两个函数没有延时一直重绘。

这里,我们看一下μc/GUI 中一个重要的函数——GUI_Delay();,这个函数并非简单
的一段延时,而是不断的调用 GUI_Exec();函数来进行重绘操作,直到剩余的时间小于 5
个时间单位时才原地等待或进行任务调度

因而,当用户移植了操作系统之后,可以有两种方法建立任务进行重绘:

引起重绘的原因

对于μc/GUI 图形界面来说,窗口是图形界面上可见事物的基本单位——如控件就是
以窗口为基础的,故而重绘总是指窗口上的内容需要重新绘制。μc/GUI 的重绘可以根据
每个阶段要完成的功能分为如下三个部分:
(1)因某种操作导致μc/GUI 设置了无效区域和无效窗口
(2)在 GUI_Exec();或 WM_Exec();中遍历窗口链查找无效窗口,向满足重绘条件的
无效窗口所代表的的控件的系统级回调函数发出 WM_PAIT 重绘消息
(3)该窗口所代表的的控件的系统级回调函数接收到 WM_PAINT 消息, 在其重绘函
数中进行实际的绘制工作
在这三部分中,第(1)部分总是能够立即被执行的,而由于为了能够优先保证响应
用户的操作等因素,(2)(3)部分只有当用户无更高优先级操作时开始执行绘制工作,每
次有且只有一个无效窗口能够绘制完成。
可见,μc/GUI 进行重绘的前提条件是——μc/GUI 中出现了无效窗口,出现无效窗
口的原因有以下几种:
(1)一个带有可见属性 WM_CF_SHOW 的窗口刚刚被创建时被设置为无效窗口
(2)一个窗口在创建后,由于某种操作导致窗口上出现了无效区域而成为无效窗口
三、成为无效窗口的判断条件及步骤

窗口 hWin 的属性集 WM_H2P(hWin)->Status 每一位都代表着窗口的一种属性,当窗
口拥有了某一种属性之后,窗口属性集 Status 中的某一位就被设置为 1。如当一个窗口被
设置为无效窗口时,就意味着该窗口属性集 Status 中的 WM_SF_INVALID 位将被设置为 1,
同时修改μc/GUI 中统计当前无效窗口数目的变量 WM__NumInvalidWindows。关于窗口
无效属性的定义如下:
#define WM_SF_INVALID WM_CF_ACTIVATE
#define WM_CF_ACTIVATE (1<<5)
然而当把一个窗口由有效窗口转变为无效窗口时,并非简简单单的将窗口属性集
Status 中的无效位修改为 1 即可,有些特殊的窗口并不能被设置为无效窗口(不可见窗口)
或将导致其他窗口设置为无效窗口(透明无形窗口)。
首先,我们介绍一下需要用到的几种窗口属性:
 

属性名属性位意义
无效位(有效/无效)WM_SF_INVALID(1<<5)窗口无效,需要重绘
可见位(可见/不可见)WM_SF_ISVIS(1<<1)窗口是可见的
透明位(透明/不透明)WM_SF_HASTRANS(1<<0)窗口是透明的
有形位(有形/无形)WM_SF_OUTLINE(1<<11)与透明位配合使用,不单独使用




那么什么样的窗口不能被设置为无效窗口呢?(满足任何一个条件即可)
(1)不可见窗口
(2)透明无形窗口
那么什么样的窗口才能被设置为无效窗口呢?(满足任何一个条件即可)
(1)可见、非透明窗口
(2)可见、透明有形窗口
判断步骤
_Invalidate1Abs();函数的代码如下所示:
/*********************************************************************
*
* _Invalidate1Abs
*在一个给定绝对坐标的无效矩形区域,判断是否应该将一个窗口设置为无效窗口
* Invalidate given window, using absolute coordinates
*/
static void _Invalidate1Abs(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r;
WM_Obj* pWin;
int Status;
pWin = WM_H2P(hWin);
Status = pWin->Status;
if ((Status & WM_SF_ISVIS) == 0) {
return; /* Window is not visible... we are done */
}
if ((Status & (WM_SF_HASTRANS | WM_SF_CONST_OUTLINE)) == WM_SF_HASTRANS) {
return; /* Window is transparent; transparency may change... we are done, since background will be invalidated */
}
if (WM__RectIsNZ(pRect) == 0) {
return; /* Nothing to do ... */
}
/* Calc affected area */
GUI__IntersectRects(&r, pRect, &pWin->Rect);
if (WM__RectIsNZ(&r)) {
#if WM_SUPPORT_NOTIFY_VIS_CHANGED
WM__SendMsgNoData(hWin, WM_NOTIFY_VIS_CHANGED);
/* Notify window that visibility may have changed */
#endif
if (pWin->Status & WM_SF_INVALID) {
GUI_MergeRect(&pWin->InvalidRect, &pWin->InvalidRect, &r);
} else {
pWin->InvalidRect = r;
pWin->Status |= WM_SF_INVALID;
马宽:嵌入式图形界面系统μc/GUI 的原理分析及应用
- 75 -
WM__NumInvalidWindows++;
/* Optional code: Call external routine to notify that drawing is required */
#ifdef GUI_X_REDRAW
{
GUI_RECT r;
r = pWin->Rect;
if (WM__ClipAtParentBorders(&r, hWin)) {
GUI_X_REDRAW(); /* Call hook function to signal an invalidation 预留给用户的钩子函数 */
}
}
#endif
GUI_X_SIGNAL_EVENT(); //预留给用户的钩子函数
}
/* Debug code: shows invalid areas 调试专用*/
#if (WM_SUPPORT_DIAG)
if (WM__pfShowInvalid) {
(WM__pfShowInvalid)(hWin);
}
#endif
}
}
由以上代码可知,在一个给定的绝对坐标的无效矩形区域 pRect,判断是否应该将一
个窗口 hWin 设置为无效窗口的步骤如下:
(1)若该窗口为不可见窗口,则该窗口不可能在屏幕 LCD 上显现,所以无需修改无
效矩形、执行重绘操作,返回
(2)若该可见窗口为透明无形窗口,则该窗口将在屏幕 LCD 上显示其 Z 前序窗口,
其本身也在屏幕 LCD 上不可见,所以同样无需修改无效矩形、执行重绘操作,返回
(3)若该绝对坐标矩形区域的大小为 0 (矩形大小为 0 的意思见 4.5.1 节“坐标惯例”),
那么认为不需要在该窗口上修改无效矩形、执行重绘操作,返回
(4)若绝对坐标矩形区域在该窗口中进行“修剪”,若“修剪”后剩下的矩形大小为
0,那么认为不需要在该窗口上修改无效矩形、执行重绘操作,返回
(5)经过前四步判断后,说明确实需要且能够在该窗口上新添加一块无效区域,根
据窗口原本是否为无效窗口而分两种情况对待:
1)原本为无效窗口——窗口属性集 Status 的 WM_SF_INVALID 位为 1
将经过“修剪”后的绝对坐标无效矩形与该无效窗口原来的无效矩形
InvalidRect 取“并集”作为该无效窗口新的无效矩形 InvalidRect,见下图 7.1
2)原本是有效窗口——窗口属性集 Status 的 WM_SF_INVALID 位为 1
A. 由于原本为有效窗口,所以直接修改窗口的无效矩形为“修剪”后绝对坐
标的矩形
B. 修改窗口属性集 Status 的 WM_SF_INVALID 无效位为 1, 表示窗口成为无
效窗口
C. 将μc/GUI 记录无效窗口数目的 WM__NumInvalidWindows 加一

无效窗口的无效区域 InvalidRect 决定了该无效窗口接收到 WM_PAINT 重绘消息时重
绘的区域的最大范围,这个范围在具体绘制时需要经过“修剪”、“剪切”才能决定实际绘
制区域,取决于无效区域 InvalidRect 上该窗口的 Z 序。

四、设置一块无效区域

void WM_InvalidateArea(const GUI_RECT* pRect) {
  WM_HWIN   hWin;
  WM_LOCK();
  /* Iterate over all windows */
  for (hWin = WM__FirstWin; hWin; hWin = WM_H2P(hWin)->hNextLin) {
    WM__Invalidate1Abs(hWin, pRect);
  }
  WM_UNLOCK();
}

 

五、设置无效窗口

WM_InvalidateWindow->WM_InvalidateRect(hWin, NULL);

void WM_InvalidateWindow(WM_HWIN hWin) {
  WM_InvalidateRect(hWin, NULL);
}

void WM_InvalidateRect(WM_HWIN hWin, const GUI_RECT*pRect) {
  GUI_RECT r;
  WM_Obj* pWin;
  int Status;
  if (hWin) {
    WM_LOCK();
    pWin = WM_H2P(hWin);
    Status = pWin->Status;
    if (Status & WM_SF_ISVIS) {  // 窗口状态是可见
      r = pWin->Rect;//此窗口大小
      if (pRect) {
        GUI_RECT rPara;
        rPara = *pRect;
        WM__Client2Screen(pWin, &rPara);// 转换成绝对坐标 窗口内部
        GUI__IntersectRect(&r, &rPara); // 计算出窗口 无效部分
      }
      if (WM__ClipAtParentBorders(&r, hWin)) {      /* Optimization that saves invalidation if window area is not visible ... Not required */
        if ((Status & (WM_SF_HASTRANS | WM_SF_CONST_OUTLINE)) == WM_SF_HASTRANS) {
          WM__InvalidateRectEx(&r, pWin->hParent, pWin->hNext);
        } else {
          WM__Invalidate1Abs(hWin, &r);
        }
      }
    }
    WM_UNLOCK();
  }
}

上面代码,在μc/GUI 对某一个控件或窗口的相关属性修改之后,通常因此需要对它们进行重绘,
所以就调用 WM_InvalidateWindow();函数将该窗口设置为无效窗口从而以后对它们进行
重绘。设置“无效窗口”将转化为“设置相对于某一个窗口的相对坐标的矩形区域为无效
区域”, WM_InvalidateRect();的第二个参数为指向相对坐标矩形的指针,当指针为空时,
将以为着相对坐标矩形为整个窗口 hWin 的矩形区域 WM_H2P(hWin)->Rect。
如果该窗口为可见的且透明无形无效窗口, 那么会将与无效区域交叉的该窗口的 Z 前
序窗口全部设为无效窗口,执行重绘操作;如果该窗口为其他可见窗口,那么仅仅将该窗
口设置为无效窗口
 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值