BREW的Widget实现分析(一)

一,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强得多的关系,所以如果可能的话,推荐使用getset函数来表达has-a的关系。
2:其实普通的接口指针,如 IWidget * IContainer * 等,都是指向虚函数表的2级指针。因为是2级指针,增加了相当的灵活性(还记得那著名的添加一个间接层的名言吗)。
5,Draw函数
当显示Container时,container会遍历所有的widget,并调用IWIDGET_Draw函数完成显示操作

Widget1
Container(wid2, wid3)
Widget3
                              IContainer( 0x11111111 )

                      
              
                              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。

相关内容推荐