一,WidgetBase及其作用
1,结构体的定义
struct WidgetBase {
const AEEVTBL(IWidget) *pvt;
int nRefs;
IModule * piModule;
WExtent extent;
IContainer * piContainer;
IModel * piModel;
HandlerDesc hd;
PFNHANDLER pfnDefHandler;
// view model
IModel * piViewModel;
};
2,各字段的说明
字段名
|
说明
|
pvt
|
虚函数表的指针
|
nRefs
|
引用计数
|
piModule
|
所属的Module的指针
|
extent
|
Widget的大小,宽度,高度
|
piContainer
|
widget所属container的指针
|
piModel
|
Widget为根据MVC模型而作的,Model的指针
|
hd
|
在该widget上有event发生时,调用该处理函数。
|
pfnDefHandler
|
默认的event处理函数
|
piViewModel
|
|
3,该结构体定义了所有widget公用的数据成员。当然也提供了公用的函数,如WidgetBase_XXX等函数群。具体的widget 的实现类,都以该结构体作为第一个成员。
二,ContainerBase及其作用
1,container的简单说明
widget的容器,而container又可以看作是一种特殊的widget。这里就是一个composite模式。
2,WidgetNode
Container中的所有widget的相关信息放在一个双向链表中。链表的节点的定义如下:
struct WidgetNode {
WidgetNode * pNext;
WidgetNode * pPrev;
IWidget * piWidget;
AEERect rc;
// if non-null, then this widget is raised
IXYContainer * pixyRaise; // xy container that widget is raised to
#if defined(OPTIMIZ3)
AEERect rcDraw;
#endif
flg fVisible : 1;
flg fDraw : 1;
};
pNext,pPrev构成了双向链表;piWidget就是容器中的一个widget的指针;rc代表了该widget的位置,及大小。
对容器的操作,如添加widget,删除widget,查找widget,遍历所有的widget等,都映射为对该链表的操作。
3,结构体定义
struct ContainerBase
{
AEEVTBL(IContainer) * pvt;
uint32 nRefs;
IModule * piModule;
IModel * piModel;
WExtent extent;
IContainer * piParent;
IWidget widget;
AEEVTBL(IWidget) vtWidget;
Border border;
IModel * piViewModel;
HandlerDesc hd;
PFNHANDLER pfnDefHandler;
WidgetNode head;
…
};
4,字段说明
字段
|
说明
|
pvt
|
指向IContainer的虚函数表
|
从nRefs 到
piParent,
及hr和
pfnDefHandler
|
同WidgetBase的意义完全相同,因为要把Container看作一个普通的widget
|
widget
|
IWidgetVtbl *pvt ; 指向结构体的下一个字段vtWidget;
就是通过这一个虚函数表,是该
container
可以被认为是一个普通的
widget
。当调用
ICONTAINER_QueryInterface( IWidget )
时,返回该指针的地址。
ContainerBase * pMe ; 其实就是this指针
|
vtWidget
|
Widget的虚函数表,通过该表,使container可以被认为是一个普通的widget。
|
head
|
包含的Widget组成的链表
|
摘抄的代码如下:
int ContainerBase_QueryInterface(IContainer *po, AEECLSID id, void **ppo)
{
if ((id == AEEIID_WIDGET)
|| (id == AEEIID_HANDLER)) {
*ppo = &me->widget;
ICONTAINER_AddRef(po);
return SUCCESS;
}
}
当客户通过该指针调用IWidget接口的方法时,
(*(IWidgetVtbl**)(void*)ptr)->AddRef();
*ptr为字段pvt的值,即指向IWidgetVtbl结构体的指针。上述语句只不过是添加了强制类型转换。
通过这里我们可以清楚地了解到,把IContainer当作是普通的widget来看待时,它和该container里有多少个widget并没有关系,并且也不是其中的任何一个widget。
注
1
:其实
QueryInterface
的意思就是
object-oriented
中的
“
is-a
”的关系,即继承关系,而按照
object-oriented
的原则,
is-a
是比
has-a
强得多的关系,所以如果可能的话,推荐使用
get
,
set
函数来表达
has-a
的关系。
注
2
:其实普通的接口指针,如
IWidget *
,
IContainer *
等,都是指向虚函数表的
2
级指针。因为是
2
级指针,增加了相当的灵活性(还记得那著名的添加一个间接层的名言吗)。
5,Draw函数
当显示Container时,container会遍历所有的widget,并调用IWIDGET_Draw函数完成显示操作
Widget1
Container(wid2, wid3)
Widget3
|
IWidget( 0x22222222 )
三,Decorator的实现方法
1,说明
Decorator是一种特殊的container,它管理并且只管理一个widget。它向该widget添加更多的UI功能
2,结构体
struct WidgetContBase {
WidgetBase base;
IContainer container;
AEEVTBL(IContainer) vtContainer;
};
struct Decorator {
WidgetContBase base;
IWidget * pChild;
};
3,结构体说明
字段
|
说明
|
Base
|
说明该组件是一个普通的widget
|
container
|
IContainerVtbl *pvt ; 指向结构体的下一个字段vtContainer;
就是通过这一个虚函数表,是该
decorator
可以被认为是一个
container
。当调用
IDECORATOR_QueryInterface( IContainer )
时,返回该指针的地址。
WidgetContBase * pMe ; 其实就是this指针
|
vtContainer
|
Container的虚函数表,通过该表,是widget(decorator)可以被认为是一个container。
|
pChild
|
被decorated的target widget。
|
摘抄的代码如下:
int WidgetContBase_QueryInterface(IWidget *po, AEECLSID clsid, void **ppo)
{
WidgetContBase *me = (WidgetContBase*) po;
if (clsid == AEEIID_CONTAINER) {
*ppo = (void *)&me->container;
WidgetBase_AddRef((IWidget*)po);
return SUCCESS;
}
return WidgetBase_QueryInterface(po, clsid, ppo);
}
可以看出:
IContainer本身是一个container,但是可以把它作为widget来看待。
IDecorator本身是一个widget,但是可以把它作为container来看待。
4,如果IDecorator已经wrap了target widget的话,那么调用ICONTAINER_GetWidget可以得到target widget。
IROOTCONTAINER_GetFirstWidget返回最先被加入的widget。
IROOTCONTAINER_GetLastWidget返回最后被加入的widget。