uCGUI 的窗体管理主要采用了 WM_Obj 的窗体数据结构,在该结构中采用两种方式记录窗体:
一种是链表形式,一种多叉树的形式。
第一种记录所有的窗口,第二种记录当前窗口和其兄弟窗口所在的位置。
WM_Obj 的结构体如下:

typedef struct
{
  GUI_RECT Rect;        /* outer dimensions of window */
  GUI_RECT InvalidRect; /* invalid rectangle */

  WM_CALLBACK* cb;      /* ptr to notification callback */

  WM_HWIN hNextLin;     /* Next window in linear list */
  WM_HWIN hParent, hFirstChild, hNext;

  U16 Status;           /* Some status flags */
} WM_Obj;

首先,我们看看 uCGUI 怎么建起这棵窗口管理树的

uCGUI每创建一个窗口是通过 WM_CreateWindowAsChild 函数来申请的,在这个函数中,主要是为新的窗口申请空间,初始相关的 rect 和回调函数等,并建立或者加入新的节点到树中和链表中,然后发送 WM_CREATE 到回调函数中初始化窗口。具体的代码见uCGUI源代码 WMWM.c 。

我们主要来看看窗口管理的建立与加入。

下面的图,每个子节点的 hParent 都有指向父节点:

Eastar:
以下内容详见: void WM__InsertWindowIntoList(WM_HWIN hWin, WM_HWIN hParent)

(1).当新建窗口时,其父窗体无子节点时:

Eastar:
当准备新建窗口 Child 时,发现 pParent->hFirstChild 为 0 ,则认为 pParent 还没有子节点。

(2).见图2(参照图1),当新建窗口时(Status 包含 WM_SF_STAYONTOP),其父窗体有子节点,且子节点的 Status 为 WM_SF_STAYONTOP

Eastar:
假设图1的 pParent->hFirstChild 默认指向的第1个节点 Child 为 Child1;(这样假设是为了图2的说明)
我的理解: 当 Parent 已经指向 Child1 时,如果需要新建的 Child2(标注的Status包含有 WM_SF_STAYONTOP ),则将 Parent 先指向 Child2 ,然后再让 Child2 的 hNext 执行 Child1 。
目的是让新建的窗口 Child2 处于最顶层。
WM_SF_STAYONTOP:让当前对应的窗口处于窗口的最前面;

(3).见图3,当新建窗口时,其窗体不为 WM_SF_STAYONTOP ,且父窗口子节点不为WM_SF_STAYONTOP

(4).见图4,当新建窗口时,其窗体不为WM_SF_STAYONTOP,其父窗口子节点为WM_SF_STAYONTOP

接着,uCGUI把所有的窗口统一放到了一个LINKLIST(结构体中hNextLin)中,用于更方便管理窗口。

OK,到这里也了解了uCGUI WM的建立和构成,看其相关函数做了什么动作。

WM_HWIN WM_GetParent(WM_HWIN hWin):

当前节点,通过其hParent获取其父节点。

WM_HWIN WM__GetFirstSibling(WM_HWIN hWin):

获取其兄弟节点,在整个水平线中的首个,即父节点的hFirstChild

WM_HWIN WM__GetPrevSibling(WM_HWIN hWin):

获取当前节点的前一个兄弟节点

WM_HWIN WM__GetLastSibling(WM_HWIN hWin):

获取当前节点的最后一个兄弟节点

void WM_BringToBottom(WM_HWIN hWin):

把当前窗口带到最底,即把窗口放到父节点的hFirstChild

void WM_BringToTop(WM_HWIN hWin):

把当前节点放到同水平线上的最后,如果是hFirstChild需重新给其父节点指定FIRST CHILD值(hFirstChild这里不画出图)

int WM_BroadcastMessage( WM_MESSAGE* pMsg):

把消息发送到每个窗口中,利用WM_OBJ中的LINKLIST,因为有WM__FirstWin,所以根据这个遍历LINKLIST,并通过WM_SendMessage调用每个窗口的回调函数。

void WM_EnableWindow(WM_HWIN hWin):

void WM_DisableWindow(WM_HWIN hWin):

这里是通过发送WM_SET_ENABLE消息,让窗口回调函数自己处理


来源: https://blog.csdn.net/jacklam200