本文以FrameWindow为对象,粗略的讲述了如何扩展CEGUI库,从而添加一个全新的基础控件类型。
如果你使用过FrameWindow,那么你一定可以发现,FrameWindow的4个角落都可以进行缩放。
如果我们需要固定某个角呢?比如制作一个聊天框,它可以放大缩小,但是左下角锚定。
最开始我一个个的看例子,似乎除了4角全缩放,就是不能缩放,看来例子里没有我们需要的。
再去看FrameWindow的头文件和CPP文件,只有一个关于设置是否可以缩放的函数SetSizingEnable(bool Setting),和几个protected属性、根据鼠标坐标来判断是否进行缩放的函数。
看来FrameWindow派生时,没有做锚定某个角的处理。那么就去Window的头文件和CPP文件里找找吧。
很可惜结果也是没有。
现在的解决方法有2种:
1、修改或继承FrameWindow,使之支持锚定角落。
2、编写函数,响应EventMouse DOWN、Move、UP事件,使具体对象支持锚定缩放。
我选择了前者。因为这样修改之后的FrameWindow更加方便,而且我也讨厌去计算那些烦人的坐标,何况FrameWindow里本身就有计算这些坐标的内部方法。
OK,我们需要做的就是定义下规则:
// AchorCorner
#defineAnchorLeftTop 0x01
#define AnchorLeftBottom 0x02
#define AnchorRightTop0x04
#define AnchorRightBottom 0x08
然后我们定义关于锚定的变量
private:
int d_anchorCorner;
之后我们需要在构造函数里添加关于我们的变量的初始化。因为我们希望对FrameWindow的改变不会对其原有的行为有所影响。因此我们将锚定点设置为:
d_anchorCorner = 0;
再来我们定义关于设置锚定的方法:
public:
void setAnchorCorner( int anchorCorner);
intgetAnchorCorner( void);
并且实现他们,先是获取对象的锚定状态:
int FrameWindow::getAnchorCorner(void)
{
return d_anchorCorner;
}
然后是设置锚定,在这里,我采用以下规则:“锚定角由用户给出,如果该角落已经被设置,则将这个角取消”。这样,我们的set函数就可以给对象既添加锚定信息,又可以删除锚定信息了:
void FrameWindow::setAnchorCorner( int anchorCorner)
{
if ( d_anchorCorner & anchorCorner)
d_anchorCorner^= anchorCorner;
else
d_anchorCorner |= anchorCorner;
}
现在我们重新编译一下CEGUI工程里的CEGUIBase,让它重新生成一个dll(DEBUG)和LIB(DEBUG_Static)。并且将原来的替换掉,就可以使用我们刚刚修改的FrameWindow了--只是在代码里。
好吧,现在我们已经开始往CEGUI的源代码里胡乱加代码了,因此一切都会变的不那么顺畅。实际上我想说的就是,你的LayoutEdit识别不出来这个FrameWindow了,如果要Add的话,会使劲的抛异常!
你可以试试不用布局器,而是写代码来进行界面布局。相信我,你一定会被统一坐标系统弄疯。
我的解决方案就是:全盘COPY一次FrameWindow的代码,然后添加改动,把它改个名字,比如frame2,然后作为一个新的控件使用。但是没完,我们还需要为这个控件添加属性。这个可以全盘照抄FrameWindowProperty.h和.cpp。
上个步骤不难,不过在这里还是想提醒下大家,注意命名的统一。
接着,为了配合我们的新控件frame2,我们需要
在Scheme文件里Copy映射,并修改相应名称。
你也可以在视感文件里COPY FrameWindow的外观配置,然后尝试着修改一下。(我尝试将默认背景改为透明背景时,这一步对我来说异常痛苦...我恨XML...),或者直接使用FrameWindow的外观来作为frame2的外观--它们俩长的完全一样!(在这里我使用Taharez风格的相关文件进行的实验。)
去LayoutEdit看看,它还是抛异常。肯定有什么不对劲的地方,从异常提示的信息可以看到,我们的frame2不在WindowFactory的创建列表里面。
OK,这表明我们还没有完全的COPY FrameWindow。为了能让WindowFactory顺顺当当的创建我们的frame2,接着找找关于FrameWindow的代码,看看我们有没有漏掉什么include ,或者 大规模的添加控件的代码。通过搜索整个解决方案,有以下几个文件跟工厂和FrameWindow相关:
CEGUI.h(75)
CEGUIBaseFactories.cpp(43)
CEGUIBaseFactories.h(45)
CEGUIBaseFactories.h(80)
CEGUIForwardRefs.h(88)
照着改就行。
先在代码里测试下frame2这个新玩意,如果我没有漏掉什么的话,你应该可以用代码创建一个frame2窗口,它和FrameWindow一模一样,除了多了个缩放锚定功能。
以上做的事对我来说有点烦琐,或者中间穿插了一些别的事情,总之我弄了1天...最后思维敏捷度降为负数,人完全处于放空状态了.oO。现在回头再看我做的事情,只记得当时人搞的晕晕的,但好象都是些CVCV,然后修改下名字...
照着FrameWindow做个frame2出来不难,同时这也是很好的练习目标,在完成之前,我在这里等你。
好了,现在我不得不告诉你一个噩耗:LayoutEdit依然不支持我们的frame2!而且报的错误还是frame2这个类型在工厂里不存在。
恩,LayoutEdit的文件夹下面有个ceguibase.dll,让我们来编译一个Release版本的dll扔进去看看?
满怀希望的运行LayoutEdit,结果还是报错!
OK,肯定还有什么地方是我没研究到的,不过这已经属于辅助工具开发的范畴了。当然将来在项目运用中,肯定会修改LayoutEdit,使它更加完善和强大,但这不是研究CEGUI本身的事情,所以对这个问题,我觉得暂时就放一放吧。等将来更加熟悉CEGUI的时候再回头来解决我们一路遗留下来的知识盲点。
可是总得有个解决方案,不是吗?以下是我的解决方法:
假设你在Scheme文件里将frame2映射为“Taharez/Frame2”,
那么你可以在LayoutEdit里添加FrameWindow,
然后手工修改.layout文件里面的Taharez/FrameWindow,改为Taharez/Frame2。
这样,在载入文件的时候,程序就生成的是我们的frame2了。
我迫切希望与大家交流,一同研究这个CEGUI,上班的时候不能上QQ,只能上MSN:[email protected]。我MSN上一个好友都没有,它还不支持QQ一样的查找和群....555
在这里对下一步的主要学习方向做个展望。
举个例子:StaticImage和StaticText 都是DefaultWindow,DefaultWindow从代码上来看,就是Window。那就是说全部的控件都可以显示一个背景图片咯?但是为什么这俩个对象一个可以显示图片,一个不能显示图片呢?
是谁在控制这些具体控件类型的表现形式?在Scheme文件里,我们可以看到,这2个控件类型的FalagardRender不同,这个渲染器模块是如何工作的?
显然我们对frame2的扩展工作还没有结束!