作者:Junhot

更新时间:2004-12-19

 

DialogControl的容器,所有的Control都必须指定自己的parentDialog。因为Dialog用以控制Control的输入及渲染。

 

Control的显示步骤如下:

1、   Dialog读取dds贴图文件;

2、   Dialog为每个Element指定贴图的矩形框、字体、颜色等信息;

3、   Dialog为每种Element类型生成相应的ElementHolder存放在defaultElementList中;

4、   各种Control通过DialogAddControl方法添加到Dialog中;

5、   AddControl方法调用InitializeControl方法将指定ControlElement索引值赋值为defaultElementList中存储的相应的ElementHolder中的Element值;

6、   DialogOnRender方法调用ControlRender方法;

7、   ControlRender方法调用DialogDrawSprite方法将自己的Element逐个显示出来。

我们一步步来看。

 

前三步的工作都是在Dialog类的InitializeDefaultElements方法中实现的,就是说一旦Dialog被实例化,就已经完成了这项工作。

 

1.  Dialog读取dds贴图文件

我们是大佬国重刑犯监狱,需要订做如下图样的囚衣:

            SetTexture(0"UI\\dxutcontrols.dds");
            SetFont(
0"Arial"14, FontWeight.Normal);


 

2.  Dialog为每个Element指定贴图的矩形框、字体、颜色等信息

截取其中Button控件的代码说明(囚衣的详细尺寸及图样如下):

 

Element e = new Element();
……
//-------------------------------------
// Button - Button
//-------------------------------------
e.SetTexture(0new System.Drawing.Rectangle(0,0,136,54));
e.SetFont(
0);
e.TextureColor.States[(
int)ControlState.Normal] = new ColorValue(1.0f1.0f1.0f0.55f);
e.TextureColor.States[(
int)ControlState.Pressed] = new ColorValue(1.0f1.0f1.0f0.85f);
e.FontColor.States[(
int)ControlState.MouseOver] = BlackColorValue;
// Assign the element
SetDefaultElement(ControlType.Button, Button.ButtonLayer, e);

//-------------------------------------
// Button - Fill Layer
//-------------------------------------
e.SetTexture(0new System.Drawing.Rectangle(136,0,136,54), TransparentWhite);
e.TextureColor.States[(
int)ControlState.MouseOver] = new ColorValue(1.0f1.0f1.0f0.6f);
e.TextureColor.States[(
int)ControlState.Pressed] = new ColorValue(0,0,00.25f);
e.TextureColor.States[(
int)ControlState.Focus] = new ColorValue(1.0f1.0f1.0f0.05f);
// Assign the element
SetDefaultElement(ControlType.Button, Button.FillLayer, e);

囚衣当然分上衣和裤子了,当然女囚犯要穿连衣裙也不是不可以……或者还有人喜欢戴帽子……

可以看到整个Button分为两个ElementButton本身和它的Fill LayerControlElement等之间的关系下篇文章再说吧)。首先,创建一个新的Element实例,给这个实例的贴图、字体、颜色等赋值。

 

这里的两个SetTexture方法中的矩形参数是干什么的呢?实际上,这个矩形就是对上面载入的dds贴图文件的裁减矩形。

第一个:Button – Button中的System.Drawing.Rectangle(0,0,136,54),这里是Button的原始状态,这里存放的是Button初始状态的贴图矩形;

第二个:Button – Fill Layer中的System.Drawing.Rectangle(136,0,136,54),这里存放的是鼠标移到Button上面的贴图矩形。

 

3. Dialog为每种Element类型生成相应的ElementHolder存放在defaultElementList

好!囚衣做好啦,先放进仓库吧,有囚犯来了就马上可以穿了。

设置好Element的各项参数后,Dialog通过SetDefaultElement方法讲该Element包裹在ElementHolder中,设置该ElementHolder的类型为指定的Control类型,并说明该Element在这个Control中的索引值,然后将holder存放在defaultElementList相应的位置备用:

/// <summary>
/// Sets the default element
/// </summary>

public void SetDefaultElement(ControlType ctype, uint index, Element e)
{
    
// If this element already exists, just update it
    for (int i = 0; i < defaultElementList.Count; i++)
    
{
        ElementHolder holder 
= (ElementHolder)defaultElementList[i];
        
if ( (holder.ControlType == ctype) &&
            (holder.ElementIndex 
== index) )
        
{
            
// Found it, update it
            holder.Element = e.Clone();
            defaultElementList[i] 
= holder;
            
return;
        }

    }


    
// Couldn't find it, add a new entry
    ElementHolder newEntry = new ElementHolder();
    newEntry.ControlType 
= ctype;
    newEntry.ElementIndex 
= index;
    newEntry.Element 
= e.Clone();

    
// Add it now
    defaultElementList.Add(newEntry);
}


 

也就是说,在Dialog创建时,就已经将所有控件的样式定下来了。

 

4.  各种Control通过DialogAddControl方法添加到Dialog

咦?这么快就拉来一车囚犯!?老大,我会忙不过来的!来来,排队登记!

首先,控件通过如下语句从parentDialog中创建:

Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);

 

我们来看看Dialog内部是如何添加它的:

        /// <summary>Adds a button control to the dialog</summary>
        public Button AddButton(int id, string text, int x, int y, int w, int h, System.Windows.Forms.Keys hotkey, bool isDefault)
        
{
            
// First create the button
            Button b = new Button(this);

            
// Now call the add control method
            AddControl(b);

            
// Set the properties of the button now
            b.ID = id;
            b.SetText(text);
            b.SetLocation(x, y);
            b.SetSize(w,h);
            b.Hotkey 
= hotkey;
            b.isDefault 
= isDefault;

            
return b;
        }


很简单的创建实例并给属性赋值的过程。这个过程调用了AddControl方法:

        /// <summary>
        
/// Adds a control to the dialog
        
/// </summary>

        public void AddControl(Control control)
        
{
            
// Initialize the control first
            InitializeControl(control);

            
// Add this to the control list
            controlList.Add(control);
        }

AddControl做了两件事,首先将该Control初始化,然后将它加入自己的controlList中。

 

5.  AddControl方法调用InitializeControl方法将指定ControlElement索引值赋值为defaultElementList中存储的相应的ElementHolder中的Element

那么Control是如何被初始化的呢?

嗯,你今天是囚犯3527了,看看仓库里面有没有你能穿的囚衣。这个尺寸的囚衣适合你啦,上衣和裤子都合适,还附送一顶帽子……喂!别把裤子套头上啦。

/// <summary>
/// Initializes a control
/// </summary>

public void InitializeControl(Control control)
{
    
if (control == null)
        
throw new ArgumentNullException("control""You cannot pass in a null control to initialize");

    
// Set the index
    control.index = (uint)controlList.Count;

    
// Look for a default element entires
    for (int i = 0; i < defaultElementList.Count; i++)
    
{
        
// Find any elements for this control
        ElementHolder holder = (ElementHolder)defaultElementList[i];
        
if (holder.ControlType == control.ControlType)
            control[holder.ElementIndex] 
= holder.Element;
    }


    
// Initialize the control
    control.OnInitialize();
}


首先,Dialog为这个Control编个号,然后,Dialog在他的defaultElementList中寻找与该Control相同类型的预定义的Element,并通过Control里的Element索引器将预定义的Element赋值给该Control的各个Element

 

疑问:control不是单独的实例对象吗?为什么这里能用数组的方式赋值呢?

回答:这是C#中的索引器语法,参见:

     .NET Famework SDK文档-〉参考-〉编译器和语言参考-C#-C#语言规范-10.8 索引器

 

6.DialogOnRender方法调用ControlRender方法

囚衣穿好了没?今天是监狱开放日!顺便展示一下我们的新款囚衣。

报告,广场太小了,站不下这么多人……

那……那改天再拉你们出去游街吧……

DialogOnRender中有如下的渲染Control的代码:

// If the dialog is minimized, skip rendering
// its controls.
if (!isDialogMinimized)
{
    
for(int i = 0; i < controlList.Count; i++)
    
{
        
// Focused control is drawn last
        if (controlList[i] == controlFocus)
            
continue;

        (controlList[i] 
as Control).Render(device, elapsedTime);
    }


    
// Render the focus control if necessary
    if (controlFocus != null && controlFocus.Parent == this)
        controlFocus.Render(device, elapsedTime);
}


 

如果Dialog没有最小化,那么循环调用controlList中各个ControlRender方法。

 

7.  ControlRender方法调用DialogDrawSprite方法将自己的Element逐个显示出来

囚犯:唉……我没自由、失自由……出去放风都要人看着,还得穿上囚衣……

 

/// <summary>Render the button</summary>
public override void Render(Device device, float elapsedTime)
{
    ……
    
// Background fill layer
    Element e = elementList[Button.ButtonLayer] as Element;
    
float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;

    System.Drawing.Rectangle buttonRect 
= boundingBox;
    buttonRect.Offset(offsetX, offsetY);

    
// Blend current color
    e.TextureColor.Blend(state, elapsedTime, blendRate);
    e.FontColor.Blend(state, elapsedTime, blendRate);

    
// Draw sprite/text of button
    parentDialog.DrawSprite(e, buttonRect);
    parentDialog.DrawText(textData, e, buttonRect);

    
// Main button
    e = elementList[Button.FillLayer] as Element;

    
// Blend current color
    e.TextureColor.Blend(state, elapsedTime, blendRate);
    e.FontColor.Blend(state, elapsedTime, blendRate);

    parentDialog.DrawSprite(e, buttonRect);
    parentDialog.DrawText(textData, e, buttonRect);
}


主演:

Dialog 饰 大佬国重刑犯监狱

Control 饰 囚犯