CEGUI学习笔记二-- FalagardSkinning使用手册第2章翻译

CEGUI学习笔记二-- FalagardSkinning使用手册第2章翻译

本文翻译了FalagardSkinning使用手册的第2章。

阅读完本文,你将了解如何自定义一个控件外观的方法,并且将看见自己刚刚的成果!

 

 

首先需要说明的是,这个部分不是教你如何使用XML。因此我们假定读者熟悉并知道如何使用XML。

2.1
开始前:一个空皮肤
在我们添加任何关于控件外观的代码之前,先让我们写一个XML文件的轮廓。这很简单,如下格式:


<? xml version = "1.0" ?>
< Falagard >
</ Falagard >

 

我们会把自己定义的控件外观加入到<Falagard>和</Falagard>之间。
因为可以定义很多子节点(XML特性),因此我们可以把所有的外观定义都写在一个文件里。

2.2
起步例子:Button
毫无疑问,按钮是我们在任何UI中都可以看到的、使用最多的。所以我们从Button开始。
要定义任何控件皮肤,你需要使用WidgetLook元件,并且使用name属性来给你定义的控件取一个名字。
因此开始的时候,我们会添加一个空的WidgetLook(控件外观)到外观初始化文件里:

 

< WidgetLook  name  = "TaharezLook/Button" >
</ WidgetLook >

 


查询手册(FalagardSknning.pdf)可以知道,我们必须定义几种指定特定的状态外观:
Normal
Hover
Pushed
Disabled

一旦我们查询到了哪些状态必须被定义,我们就把它们添加到外观定义中去。虽然空的定义不会显示任何东西,但最好这样做,这样至少我们的定义是完整可用的。

对于特定的显示,我们使用外观配置ImagerySection元素(节点)来描述。每一个外观配置imagery sction都有一个名字,这个名字会在之后StateImagery的Layer定义中被引用。

对于我们的按钮来说,每一个按钮状态都会有一个ImagerySection。我们把它们添加到正在制作的Button中。

 

   < WidgetLook  name  ="TaharezLook/Button" >
    
< ImagerySection  name  ="Normal_imagery" >
    
</ ImagerySection >
    
< ImagerySection  name  ="Hover_imagery" >
    
</ ImagerySection >
    
< ImagerySection  name  ="Pushed_imagery" >
    
</ ImagerySection >
    
< StateImagery  name  ="Normal" >
    
</ StateImagery >
    
< StateImagery  name  ="Hover" >
    
</ StateImagery >
    
< StateImagery  name  ="Pushed" >
    
</ StateImagery >
    
< StateImagery  name  ="Disabled" >
    
</ StateImagery >
  
</ WidgetLook >

 

现在我们可以给每一个Section定义ImageryCommpnents。这个节点将告诉系统我们的按钮显示在屏幕上会是个什么样子。
TaharezLook给按钮的每一种状态都提供了3种Imagery。(除了Disabled,在这个状态下,按钮只使用了"normal_imagery",还用了一些不同的颜色)。可用的ImagerySections向我们提供了左、中、右3个组件。
有很多方法在控件上应用这些ImagerySection,虽然我们假定按钮的绘制是 绘制两头(左、右),然后用中部件来填充这两个之间的空缺。但实际上这些象素尺寸并没有自动经过修正。之所以TaharezLook提供的图片集没出问题是因为这个图片集使用了自动缩放特性。因此如果你想使用自己所给定的外观,注意尺寸的计算,这样你才能得到预期的效果。

要指定如何绘制ImagerySection,我们需要使用ImageryCompnents。它作为ImagerySection的子节点。好了,现在我们从添加一个空的ImageryCompnent到mormal_imagery节点开始。

 

     < ImagerySection  name  ="Normal_imagery" >
      
< ImageryComponent >
      
</ ImageryComponent >
    
</ ImagerySection >

 

首先加入到ImageryComponent的是一个Area节点定义,它会告诉系统应该在哪把图象显示出来。(控件坐标)

 

       < ImageryComponent >
        
< Area >
        
</ Area >
      
</ ImageryComponent >


        
我们从配置按钮的左边开始。这是最容易配置的组件,因为我们知道一般都是(0,0)。设定这些绝对的值,我们使用AbsoluteDim。

我们使用Dim来描述需要自定义的图象显示区域。再使用子节点来给出它的值是多少:

 

       < ImageryComponent >
        
< Area >
          
< Dim  type  ="LeftEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
          
< Dim  type  ="TopEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
        
</ Area >
      
</ ImageryComponent >

 

现在已经定义了(相对父窗口的)左间距和顶间距,接下来再定义显示区域的大小。
我们希望使用图片源自己的宽度大小,要这么做的话,使用ImageDim来告诉这个元件应该访问哪个图片。

 

           < Dim  type  ="Width" >
            
< ImageDim  imageset  ="TaharezLook"
                      image 
="ButtonLeftNormal"
                      dimension
="Width" />
          
</ Dim >

 

这段代码就告诉系统 显示区域宽度的大小和外观了:
使用TaharezLook图片集里名字叫ButtonLeftNormal的图片区域,宽度为图片区域的默认值。

设置Area的最后一个部分是高度。一般来说我们希望显示高度和我们定义的高度一直。因此我们可以使用UnifiedDim或者WidgetDim来做这个事。因为不需要通过名字来查找控件,因此在这里我们选择使用更加简洁的UnifiedDim来完成。

 

           < Dim  type  ="Height" >
            
< UnifiedDim  scale  ="1.0"  type ="Height" />
          
</ Dim >


在这里我们使用缩放值1.0来表示我们需要使显示区域为整个控件的高度。

现在我们已经完成了第一个外观的Area设置。它整个的看起来是这个样子:

 

       < ImageryComponent >
        
< Area >
          
< Dim  type  ="LeftEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
          
< Dim  type  ="TopEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
          
< Dim  type  ="Width" >
            
< ImageDim  imageset  ="TaharezLook"  image  ="ButtonLeftNormal"  dimension ="Width" />
          
</ Dim >
          
< Dim  type  ="Height" >
            
< UnifiedDim  scale  ="1.0"  type ="Height" />
          
</ Dim >
          
</ Area >
      
</ ImageryComponent >

 

接下来,我们需要告诉系统显示哪张图片。我们用Image来完成这个事,它紧接着Area。

 

< Image  imageset  ="TaharezLook"  image ="ButtonLeftNormal" />

 

在ImageryComponent中需要添加的最后一个元素是VertFormat。
通过设置这个元素,我们可以通知系统在显示图片的时候,在垂直方向上做拉伸,以完全覆盖我们定义的Area显示区域。

 

       < VertFormat  type ="Stretched" />

 

现在我们完成了按钮的左部件的设置,让我们完整的来看一下:

 

       < ImageryComponent >
        
< Area >
          
< Dim  type  ="LeftEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
          
< Dim  type  ="TopEdge" >
            
< AbsoluteDim  value ="0" />
          
</ Dim >
          
< Dim  type  ="Width" >
            
< ImageDim  imageset  ="TaharezLook"  image  ="ButtonLeftNormal"  dimension ="Width" />
          
</ Dim >
          
< Dim  type  ="Height" >
            
< UnifiedDim  scale  ="1.0"  type ="Height" />
          
</ Dim >
        
</ Area >
        
< Image  imageset  ="TaharezLook"  image ="ButtonLeftNormal" />
        
< VertFormat  type  ="Stretched" />
      
</ ImageryComponent >

 

下一张需要设置的图片是右部件。我们可以精确的把显示区域设置为整个图象,但是有一个更好的办法就是,我们使用对齐格式来指明需要在右边显示。

用这样的方式来设置控件的部件也将是你使用的最多的手段,现在来看看代码是如何写的:

 

       < ImageryComponent >
        
< Area >
          
< Dim  type  ="LeftEdge" >< AbsoluteDim  value ="0" /></ Dim >
          
< Dim  type  ="TopEdge" >< AbsoluteDim  value ="0" /></ Dim >
          
< Dim  type  ="Width" >< UnifiedDim  scale  ="1.0"  type ="Width" /></ Dim >
          
< Dim  type  ="Height" >< UnifiedDim  scale  ="1.0"  type ="Height" /></ Dim >
        
</ Area >
        
< Image  imageset  ="TaharezLook"  image ="ButtonLeftNormal" />
        
< VertFormat  type  ="Stretched" />
        
< HorzFormat  type  ="RightAligned" />
      
</ ImageryComponent >

 

对于normal_imagery,最后需要设置的是中间部件。记住我们希望这个图象自动的填充另外2个部件之间的空白部分。
只需要正确的定义了图片区域就可以正确的显示了。

首先我们需要告诉系统左边距,很明显是左部件的宽度。因此我们可以通过ImageDim来得到。

         < Area >
          
< Dim  type  ="LeftEdge" >
            
< ImageDim  imageset  ="TaharezLook"
                      image 
="ButtonLeftNormal"
                      dimension 
="Width"
            
/>
          
</ Dim >
        
</ Area >

 

现在有趣的事情来了,我们需要告诉系统中间部件的宽度。如果我们知道控件的实际大小,那我们可以自己计算出精确的坐标信息。但是我们事先并不知道控件的整体宽度,因此我们需要另外的计算方法。幸运的是,我们可以通过XML语法来使系统在显示之前进行预先计算。使用DimOperator就可以搞定这个事。
在展示代码之前,让我们来看看计算公式:

中间部件的宽度=控件宽度-(右部件宽度+左部件宽度)。

同时我们还需要计算右边距:

中间部件的右边距=控件宽度-右部件宽度

好,让我们先从右边距开始:

                < Dim  type ="RightEdge" >
               
</ Dim >

 

首先我们得到控件的宽度:

                < Dim  type ="RightEdge" >
                 
< UnifiedDim  scale  = "1.0"  type ="Width" >
                 
</ UnifiedDim >
               
</ Dim >

 

然后在添加进行减法运算的代码

                < Dim  type ="RightEdge" >
                 
< UnifiedDim  scale  = "1.0"  type ="Width" >
                   
< DimOperator  op ="Subtract" >
                   
</ DimOperator >
                 
</ UnifiedDim >
               
</ Dim >

 

我们再将得到右部件宽度的代码添加到减法操作节点里去

                < Dim  type ="RightEdge" >
                 
< UnifiedDim  scale  = "1.0"  type ="Width" >
                   
< DimOperator  op ="Subtract" >
                      
< ImageDim  imageset  ="TaharezLook"
                                image 
="ButtonRightNormal"
                                dimension 
="Width"
                       
/>
                   
</ DimOperator >
                 
</ UnifiedDim >
               
</ Dim >

 

这样我们就得到了右边距的大小。
在进行更加复杂的运算之前,先来看2个关于运算先后次序的规则:
1、每一对DimOperator定义了一个操作,顺序是从最里面的DimOperator定义开始计算,然后是外层的。
2、结合律不满足实际运算,只按照DimOperator的顺序从往外开始计算。
比如:(LineSpacing + 4)*2,如果我们写成:

...
< FontDim  type  ="LineSpaceing" >
  
< DimOperator  op ="Add" >
    
< AbsoluteDim  value ="4" >
      
< DimOperator  op ="Multiply" >
        
< AbsoluteDim  value ="2" >
      
</ DimOperator >
    
</ AbsoluteDim >
  
</ DimOperator >
</ FontDim >
...

 

上面的计算公式是:4*2+LineSpacing。显然这不是我们想要的

应该是:

 

< AbsoluteDim  value ="2" >
  
< DimOperator  op ="Multiply" >
    
< AbsoluteDim  value ="4" >
      
< DimOperator  op ="Add" >
        
< FontDim  type  ="LineSpaceing" />
      
</ DimOperator >
    
</ AbsoluteDim >
  
</ DimOperator >
</ AbsoluteDim >

 

首先计算了 temp = 4+LineSpaceing;
然后将临时结果temp返回到上层,进行第2步计算 result = 2 * temp;

OK,我离题了。让我们重新回到我们的按钮显示上来。
既然计算的问题解决了,那么唯一的问题就是设置水平显示模式HorzFormat了,在这里我们将他设置为拉伸。

         < HorzFormat  Type ="Stretched" />


现在我们来看看完整的中间部件的代码

       < ImageryComponent >
        
< Area >
          
< Dim  type  ="LeftEdge" >
            
< ImageDim  imageset  ="TaharezLook"
                      image 
="ButtonLeftNormal"
                      dimension 
="Width"
            
/>
          
</ Dim >
          
< Dim  type ="RightEdge" >
            
< UnifiedDim  scale  = "1.0"  type ="Width" />
            
< DimOperator  op ="Subtract" >
              
< ImageDim  imageset  ="TaharezLook"
                      image 
="ButtonRightNormal"
                      dimension 
="Width"
              
/>
            
</ DimOperator >
          
</ Dim >
          
< Dim  type  ="TopEdge" >< AbsoluteDim  value ="0" /></ Dim >
          
< Dim  type  ="Height" >< UnifiedDim  scale  ="1.0"  type ="Height" /></ Dim >
        
</ Area >
        
< Image  imageset  ="TaharezLook"  image ="ButtonLeftNormal" />
        
< VertFormat  type  ="Stretched" />
        
< HorzFormat  Type ="Stretched" />
      
</ ImageryComponent >

现在我们已经完成了normal_imagery section的外观设置。你可以用类似的方法将另外2个外观搞定,实际上在这里例子里,你只需要根据按钮Hover或者Pushed状态来替换相关的图片名字。一切都跟我们先前配置normal_imagery时一样。

现在我们可以在各种状态节点中添加对各种外观的引用了。对外观的引用需要在Layer节点中定义。很可能在每一个Layer中都包含多个外观配置。虽然在大多数例子你,你只看到了一个Layer。
现在让我们为按钮的Normal状态来添加一个外观。

 

     < StateImagery  name  ="Normal" >
      
< Layer >
        
< Section  section ="normal_imagery" />
      
</ Layer >
    
</ StateImagery >

 

Hover和Pushed状态除了图片和名字不一样以外,其他没什么不同。

Disabled状态稍微有些不同;我们不为这个状态重新编写任何外观,我们将复用normal_imagery。但是我们将指定一些颜色,使按钮处于这种状态时显示为灰色。这个工作在Section节点中的Colours节点中完成,先来看看范例:

 

     < StateImagery  name  ="Disabled" >
      
< Layer >
        
< Section  section ="normal_imagery" >
          
< Colours
            
topLeft ="FF7F7F7F"
            topRight
="FF7F7F7F"
            bottomLeft
="FF7F7F7F"
            bottomRight
="FF7F7F7F"
          
/>
        
</ Section >
      
</ Layer >
    
</ StateImagery >

 

现在我们的按钮在各种默认状态下都有外观了。但是我们少做了一件事情:我们需要在按钮上显示一些文字。

为了指定文字,你需要使用TextComponent节点,当然可以象在ImagerySection中加入ImageryComponent节点一样,在每一个外观配置里加入TextComponent,但是这样实在是太罗嗦了。一个更好的方法是定义一个包含文本的ImagerySection,然后我们就可以在所有状态下复用了。
这样我们就从定义包含文本元件的ImagerySection开始吧:

     < ImagerySection  name  ="label" >
      
< TextComponent >
      
</ TextComponent >
    
</ ImagerySection >

 

定义一个文本元件TextComponent和定义外观元件ImageryComponent很相似,我们指定一个区域的大小和它的显示格式,用来显示文本。我们也可以通过使用Text节点来明确指示出字体和(或)字符串。如果不做这些设置,元件也可以通过控件的设置来得到这些设置。
我们希望Area居中显示,因此我们需要将文本元件的显示区域设置为整个控件。
同样我们需要为文本设置居中,因此垂直格式就象这样:
 

        < VertFormat  type  ="CentreAligned" />


水平格式就象这样:

         < HorzFormat  type  ="WordWrapCentreAligned" />


最后整个Label外观设置的定义就象这样:

     < ImagerySection  name  ="label" >
      
< TextComponent >
        
< Area >
          
< Dim  type ="LeftEdge" >< AbsoluteDim  value ="0" /></ Dim >
          
< Dim  type ="TopEdge" >< AbsoluteDim  value ="0" /></ Dim >
          
< Dim  type ="Width" >< UnifiedDim  scale ="1"  type ="Width" /></ Dim >
          
< Dim  type ="Height" >< UnifiedDim  scale ="1"  type ="Height" /></ Dim >
        
</ Area >
        
< VertFormat  type  ="CentreAligned" />
        
< HorzFormat  type  ="WordWrapCentreAligned" />
      
</ TextComponent >
    
</ ImagerySection >

现在就差往各个Layer添加这个外观了,Normal状态的代码如下:

     < StateImagery  name  ="Normal" >
      
< Layer >
        
< Section  section ="normal_imagery" />
        
< Section  section ="label" />
      
</ Layer >
    
</ StateImagery >


至于Disabled状态,则需要添加另外一些指定的颜色。

     < StateImagery  name  ="Disabled" >
      
< Layer >
        
< Section  section ="normal_imagery" >
          
< Colours
            
topLeft ="FF7F7F7F"
            topRight
="FF7F7F7F"
            bottomLeft
="FF7F7F7F"
            bottomRight
="FF7F7F7F"
          
/>
        
</ Section >
        
< Section  section ="label" >
          
< Colours
            
topLeft ="FF7F7F7F"
            topRight
="FF7F7F7F"
            bottomLeft
="FF7F7F7F"
            bottomRight
="FF7F7F7F"
          
/>
        
</ Section >
      
</ Layer >
    
</ StateImagery >

关于介绍就到这里了。需要完整的例子,以及全部其他的控件定义,可以参看CEGUI发行版的looknfeel文件夹里的文件。目录为:"cegui_mk2/Samples/datafiles/looknfeel"

 

--------------------------------------------------------------------
1、一定要按照文档的介绍,自己写一写这些代码,注意不要抄错了,否则你无法真正了解作者在说什么。当然,如果你不明白我那些翻译在说什么,一定要去看英文的。

2、编写XML文档的时候容易出错,最好导入xsd文件以验证正确性。方法为:视图-其他窗口-属性窗口-架构,将looknfeel文件夹里的falagard.xsd添加进来。这样就有语法和规则检测了。

3、我们写了这么一个Button外观配置,如果能直接看到它那该多好~
最好的途径是自己写例子来验证,比如上次我留下的作业,如果你已经实现了通过Layout文件来创建窗口,那就好验证了。不过没关系,我们也可以使用CELayoutEditor.exe来验证我们的成果。首先,这个软件是直接加载TaharezLook.scheme的,所以我们直接去对应的TaharezLook.looknfeel里,将我们的按钮添加进去,为了防止重复命名,我们把刚才写的Button外观改成Button1,或者任何你想要叫的名字。

4、现在视感文件里已经有Button1的外观了,我们再来设置falagard映射。这个很简单,到TaharezLook.scheme文件里照着Button复制一下,然后修改WindowType = "TaharezLook/Button1", LookNFeel = "TaharezLook/Button1"。

5、启动CELayoutEditor.exe,添加我们刚刚写的按钮看看?

6、现在我可以完全理解Imageset,知道looknfeel,大概知道scheme文件都是些什么东西了,不过在我完全理解以前,不会自以为是的去向大家传递错误的信息:)

原文地址http://thatax.blog.163.com/blog/static/20892680200882711318253/

你可能感兴趣的:(CEGUI学习笔记二-- FalagardSkinning使用手册第2章翻译)