BREW的Widget实现分析(一)

2019-04-15 17:21发布

  一,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。