ucgui窗口分析.docx
- 文档编号:9978667
- 上传时间:2023-02-07
- 格式:DOCX
- 页数:14
- 大小:20.36KB
ucgui窗口分析.docx
《ucgui窗口分析.docx》由会员分享,可在线阅读,更多相关《ucgui窗口分析.docx(14页珍藏版)》请在冰豆网上搜索。
ucgui窗口分析
一、相关结构体和变量
窗口管理结构体
/*窗口管理结构体共30个字节*/
structWM_Obj{
GUI_RECTRect;//窗口尺寸(x0,y0,x1,y1)8个字节
GUI_RECTInvalidRect;//无效区域(x0,y0,x1,y1)8个字节
WM_CALLBACK*cb;//回调函数4个字节
WM_HWINhNextLin;//指向链表中的下一个窗口2个字节
WM_HWINhParent;//当前窗口的父窗口2个字节
WM_HWINhFirstChild;//当前窗口的第一个子窗口2个字节
WM_HWINhNext;//下一个兄弟窗口2个字节
U16Status;//标志位2个字节
};
窗口创建的标志
#defineWM_CF_HASTRANS(1<<0)/*Hastransparency.Needstobedefinedforwindowswhichdonotfilltheentire
sectionoftheir(client)rectangle.*/
#defineWM_CF_HIDE(0<<1)/*Hidewindowaftercreation(default!
)*/
#defineWM_CF_SHOW(1<<1)/*Showwindowaftercreation*/
#defineWM_CF_MEMDEV(1<<2)/*Usememorydeviceforredraws*/
#defineWM_CF_STAYONTOP(1<<3)/*Stayontop*/
#defineWM_CF_DISABLED(1<<4)/*Disabled:
DoesnotreceivePID(mouse&touch)input*/
/*Createonlyflags...Notavailableasstatusflags*/
#defineWM_CF_ACTIVATE(1<<5)/*Ifautomaticactivationuponcreationofwindowisdesired*/
#defineWM_CF_FGND(0<<6)/*Putwindowinforegroundaftercreation(default!
)*/
#defineWM_CF_BGND(1<<6)/*Putwindowinbackgroundaftercreation*/
/*Anchorflags*/
#defineWM_CF_ANCHOR_RIGHT(1<<7)/*Rightanchor...Ifparentisresized,distancetorightwillremainconst(leftisdefault)*/
#defineWM_CF_ANCHOR_BOTTOM(1<<8)/*Bottomanchor...Ifparentisresized,distancetobottomwillremainconst(topisdefault)*/
#defineWM_CF_ANCHOR_LEFT(1<<9)/*Leftanchor...Ifparentisresized,distancetoleftwillremainconst(leftisdefault)*/
#defineWM_CF_ANCHOR_TOP(1<<10)/*Topanchor...Ifparentisresized,distancetotopwillremainconst(topisdefault)*/
#defineWM_CF_CONST_OUTLINE(1<<11)/*Constantoutline.Thisisrelevantfortransparentwindowsonly.Ifawindowistransparent
anddoesnothaveaconstantoutline,itsbackgroundisinvalidedinsteadofthewindowitself.
Thiscausesadd.computationtimewhenredrawing.*/
#defineWM_CF_LATE_CLIP(1<<12)
#defineWM_CF_MEMDEV_ON_REDRAW(1<<13)
#defineWM_CF_RESERVED3(1<<14)
#defineWM_CF_RESERVED4(1<<15)
WM_CF_SHOW、WM_CF_STAYONTOP、WM_CF_HIDE、WM_CF_ACTIVATE这几个标志是经常用到的。
二、窗口创建的过程分析
1、WM_CreateWindowAsChild
WM_HWINWM_CreateWindowAsChild(intx0,inty0,intwidth,intheight
WM_HWINhParent,U16Style,WM_CALLBACK*cb
intNumExtraBytes){
WM_Obj*pWin;
WM_HWINhWin;
WM_ASSERT_NOT_IN_PAINT();//断言,这里没有使用
WM_LOCK();
Style|=WM__CreateFlags;//给窗口的标志增加一个创建标志
/*DefaultparentisDesktop0*/
if(!
hParent){//如果不存在父窗口,比如说桌面窗口
if(WM__NumWindows){//创建桌面窗口,这个不会执行的
#ifGUI_NUM_LAYERS==1
hParent=WM__ahDesktopWin[0];//如果用户没有指定当前创建窗口的父窗口,而且该窗口
//又不是桌面窗口,默认的将桌面窗口作为其父窗口
#else
hParent=WM__ahDesktopWin[GUI_Context.SelLayer];
#endif
}
}
if(hParent==WM_UNATTACHED){
hParent=WM_HWIN_NULL;
}
if(hParent){
WM_Obj*pParent=WM_H2P(hParent);
x0+=pParent->Rect.x0;
y0+=pParent->Rect.y0;
if(width==0){
width=pParent->Rect.x1-pParent->Rect.x0+1;
}
if(height==0){
height=pParent->Rect.y1-pParent->Rect.y0+1;
}
}
if((hWin=(WM_HWIN)GUI_ALLOC_AllocZero(NumExtraBytes+sizeof(WM_Obj)))==0){
GUI_DEBUG_ERROROUT("WM_CreateWindow:
Nomemorytocreatewindow");
//如果没有空间来创建需要的动态内存块
}else{//申请动态内存成功
WM__NumWindows++;//保存系统总窗口数目的计数器加1
pWin=WM_H2P(hWin);//计算获取动态内存数据区的地址
/*向动态内存区写入当前窗口的参数*/
pWin->Rect.x0=x0;
pWin->Rect.y0=y0;
pWin->Rect.x1=x0+width-1;
pWin->Rect.y1=y0+height-1;
pWin->cb=cb;//保存回调函数
/*Copytheflagswhichcansimplybeaccepted*/
pWin->Status|=(Style&(WM_CF_SHOW|
WM_SF_MEMDEV|
WM_CF_MEMDEV_ON_REDRAW|
WM_SF_STAYONTOP|
WM_CF_DISABLED|
WM_SF_CONST_OUTLINE|
WM_SF_HASTRANS|
WM_CF_ANCHOR_RIGHT|
WM_CF_ANCHOR_BOTTOM|
WM_CF_ANCHOR_LEFT|
WM_CF_ANCHOR_TOP|
WM_CF_LATE_CLIP));
/*Addtolinkedlists*/
_AddToLinList(hWin);//将窗口插入到窗口管理链表当中
WM__InsertWindowIntoList(hWin,hParent);//插入到父窗口管理链表当中
/*根据用户定义的窗口风格进行一些列的操作*/
/*ActivatewindowifWM_CF_ACTIVATEisspecified*/
if(Style&WM_CF_ACTIVATE){//如果带激活标志的话,就激活窗口
WM_SelectWindow(hWin);/*Thisisnotneededifcallbacksarebeingused,butitdoesnotcostalotandmakeslifeeasier...*/
}
/*HandletheStyleflags,oneatatime*/
#ifWM_SUPPORT_TRANSPARENCY
if(Style&WM_SF_HASTRANS){//透明窗口
WM__TransWindowCnt++;/*Incrementcounterfortransparencywindows*/
}
#endif
if(Style&WM_CF_BGND){
WM_BringToBottom(hWin);
}
if(Style&WM_CF_SHOW){//显示窗口
pWin->Status|=WM_SF_ISVIS;//设置可视状态位
WM_InvalidateWindow(hWin);//如果有显示命令,还会设置窗口为无效,等待重绘
}
WM__SendMsgNoData(hWin,WM_CREATE);//发一个创建消息,这样创建的时候就可以在回调函数中进行处理
}
WM_UNLOCK();
returnhWin;
}
首先根据其父窗口的坐标计算出当前窗口的坐标、高度和宽度。
从动态内存区中开辟出一块窗口管理区域,然后向其中填入当前窗口的参数值。
比较重要的是接下来的两部,将当前窗口插入到窗口管理链表当中以及将窗口插入到其父窗口的同胞链表当中。
最后,如果创建的时候以显示模式WM_CF_SHOW创建,那么要为此窗口加入了可视标志WM_SF_ISVIS,而且还要设置窗口为无效。
这样在执行GUI_Exec()或者WM_Exec()的时候就会对该窗口进行重绘。
2、_AddToLinList()
staticvoid_AddToLinList(WM_HWINhNew){
WM_Obj*pFirst;
WM_Obj*pNew;
if(WM__FirstWin){//如果不是桌面窗口(事实上桌面窗口肯定存在了)
pFirst=WM_H2P(WM__FirstWin);//首先获取桌面窗口的动态内存地址
pNew=WM_H2P(hNew);//获取要插入窗口的动态内存地址
/*
*桌面窗口--->最近创建的窗口1--->更早创建的窗口2~~~~~~~--->0==>
*桌面窗口--->当前要插入的窗口--->最近创建的窗口1--->更早创建的窗口2~~~--->0
*/
pNew->hNextLin=pFirst->hNextLin;//
pFirst->hNextLin=hNew;
}else{
WM__FirstWin=hNew;//创建桌面窗口时,将桌面窗口的句柄赋给此变量
}
}
将新建窗口添加到窗口管理链表中。
这个窗口管理链表是建立在uCGUI的动态内存中,利用WM_obj类型中的成员hNextLin连接成一个单向链表。
链表的构建过程如下:
插入之前:
桌面窗口--->最近创建的窗口1--->更早创建的窗口2~~~~~~~--->0 ==>
插入之后:
桌面窗口--->当前要插入的窗口--->最近创建的窗口1--->更早创建的窗口2~~~--->0
3、WM__InsertWindowIntoList()
/*********************************************************************
*
*WM__InsertWindowIntoList
*
*Routinedescribtion
*Thisroutineinsertsthewindowinthelistofchildwindowsfor
*aparticularparentwindow.
*Thewindowisplacedontopofallsiblingswiththesamelevel.
*/
voidWM__InsertWindowIntoList(WM_HWINhWin,WM_HWINhParent){
intOnTop;
WM_HWINhi;
WM_Obj*pWin;
WM_Obj*pParent;
WM_Obj*pi;
if(hParent){//桌面窗口是不存在父窗口的
pWin=WM_H2P(hWin);//获取当前窗口的动态内存地址
pWin->hNext=0;//它的下一个兄弟窗口为0
pWin->hParent=hParent;//记录它的父窗口
pParent=WM_H2P(hParent);//获得它父窗口的动态内存地址
OnTop=pWin->Status&WM_CF_STAYONTOP;//可以用来判断此窗口是否有在最顶层的标志
hi=pParent->hFirstChild;//父窗口的第一个子窗口
/*Putitatbeginningofthelistifthereisnochild*/
if(hi==0){/*Nochildyet...Makesthingseasy!
*/
/*
*父窗口--->0====>
*父窗口--->当前窗口--->0
*/
pParent->hFirstChild=hWin;//没有子窗口,就把它作为父窗口的第一个子窗口
return;/*Earlyout...Wearedone*/
}
/*PutitatbeginningofthelistiffirstchildisaTOPwindowandnewoneisnot*/
pi=WM_H2P(hi);//获取父窗口第一个子窗口的动态内存地址
if(!
OnTop){//如果此窗口没有在最顶层的标志
if(pi->Status&WM_SF_STAYONTOP){//判断长兄是否有在最顶层的标志
/*
*父窗口--->长兄--->~~~--->0=>
*父窗口--->当前窗口--->长兄--->~~~--->0
*/
pWin->hNext=hi;//当前窗口的下一个窗口指向其长兄
pParent->hFirstChild=hWin;//父窗口的第一个子窗口为当前窗口
return;/*Earlyout...Wearedone*/
}
}
/*把它放在链表的最顶端或者在第一个“最顶层”窗口之前*/
do{
WM_Obj*pNext;
WM_HWINhNext;
if((hNext=pi->hNext)==0){/*Endofsiblinglist?
*/
pi->hNext=hWin;/*放在链表的最顶端*/
break;
}
pNext=WM_H2P(hNext);
if(!
OnTop){//如果当前窗口没有“在最顶层”的标志
if(pNext->Status&WM_SF_STAYONTOP){
pi->hNext=hWin;
pWin->hNext=hNext;
break;
}
}
pi=pNext;
}while
(1);
#ifWM_SUPPORT_NOTIFY_VIS_CHANGED
WM__NotifyVisChanged(hWin,&pWin->Rect);
#endif
}
}
将新建窗口添加到父窗口的同胞窗口管理链表中。
这个窗口管理链表是建立在uCGUI的动态内存中,利用WM_obj类型中的成员hFirstChild和hNext连接成一个单向链表。
插入的原则是:
1、如果父窗口没有孩子,直接将其作为父窗口的孩子即可。
插入之前:
父窗口--->0 ====>
插入之后:
父窗口--->当前窗口--->0
2、如果父窗口有孩子,第一个孩子有“在顶层”的标志,而当前创建的窗口没有这个标志,则将其作为其父窗口的第一个孩子。
插入之前:
父窗口--->长兄--->~~~--->0=>
插入之后:
父窗口--->当前窗口--->长兄--->~~~--->0
3、如果父窗口有孩子,第一个孩子没有“在顶层”的标志,而当前创建的窗口也没有这个标志,则将其放在同胞链表中有“在顶层”标志窗口的前边,也就是所有没有“在顶层”标志窗口的后边。
插入之前:
父窗口--->长兄(没标志)--->次兄(没标志)--->三兄(有标志)--->~~~--->0=>
插入之后:
父窗口--->长兄(没标志)--->次兄(没标志)--->当前窗口--->三兄(有标志)--->~~~--->0
4、如果父窗口有孩子,第一个孩子没有“在顶层”的标志,而当前创建的窗口有这个标志,则将其放在同胞链表的最后边。
插入之前:
父窗口--->长兄(没标志)--->次兄(没标志)--->三兄(有标志)--->~~~--->0=>
插入之后:
父窗口--->长兄(没标志)--->次兄(没标志)--->三兄(有标志)--->~~~--->当前窗口--->0
三、窗口顺序排列分析
1、按照窗口分层的概念来说,链表的头部窗口是显示在最底层,链表的尾部窗口是显示在最顶层。
在进行窗口重绘的时候,正是从链表的头部开始依次往尾部进行重绘。
2、子窗口相对于父窗口来说,子窗口在父窗口的顶部。
四、桌面窗口的创建
桌面窗口的创建发生在GUI_Init函数执行过程中。
如果系统开启了窗口管理功能,GUI_Init函数会调用WM_Init函数,在WM_Init初始化窗口管理器的时候,默认的会创建桌面窗口。
相关代码如下:
/*********************************************************************
*
*WM_Init
*/
voidWM_Init(void){
......
WM__ahDesktopWin[0]=WM_CreateWindow(0,0,GUI_XMAX,GUI_YMAX,WM_CF_SHOW,cbBackWin,0);
......
WM_InvalidateWindow(WM__ahDesktopWin[i]);
......
WM_SelectWindow(WM__ahDesktopWin[0]);
}
桌面窗口默认的回调函数
staticvoidcbBackWin(WM_MESSAGE*pMsg){
constWM_KEY_INFO*pKeyInfo;
switch(pMsg->MsgId){
caseWM_KEY:
pKeyInfo=(constWM_KEY_INFO*)pMsg->Data.p;
if(pKeyInfo->PressedCnt==1){
GUI_StoreKey(pKeyInfo->Key);
}
break;
caseWM_PAINT:
{
intLayerIndex;
#ifGUI_NUM_LAYERS>1
LayerIndex=_DesktopHandle2Index(pMsg->hWin);
#else
LayerIndex=0;
#endif
if(WM__aBkColor[LayerIndex]!
=GUI_INVALID_COLOR){
GUI_SetBkColor(WM__aBkColor[LayerIndex]);
GUI_Clear();
}
}
default:
WM_DefaultProc(pMsg);
}
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ucgui 窗口 分析