作者:Junhot
更新时间:
Dialog是Control的容器,所有的Control都必须指定自己的parentDialog。因为Dialog用以控制Control的输入及渲染。
Control的显示步骤如下:
1、 Dialog读取dds贴图文件;
2、 Dialog为每个Element指定贴图的矩形框、字体、颜色等信息;
3、 Dialog为每种Element类型生成相应的ElementHolder存放在defaultElementList中;
4、 各种Control通过Dialog的AddControl方法添加到Dialog中;
5、 AddControl方法调用InitializeControl方法将指定Control的Element索引值赋值为defaultElementList中存储的相应的ElementHolder中的Element值;
6、 Dialog的OnRender方法调用Control的Render方法;
7、 Control的Render方法调用Dialog的DrawSprite方法将自己的Element逐个显示出来。
我们一步步来看。
前三步的工作都是在Dialog类的InitializeDefaultElements方法中实现的,就是说一旦Dialog被实例化,就已经完成了这项工作。
1. Dialog读取dds贴图文件
我们是大佬国重刑犯监狱,需要订做如下图样的囚衣:
SetFont(0, "Arial", 14, FontWeight.Normal);
2. Dialog为每个Element指定贴图的矩形框、字体、颜色等信息
截取其中Button控件的代码说明(囚衣的详细尺寸及图样如下):
……
//-------------------------------------
// Button - Button
//-------------------------------------
e.SetTexture(0, new System.Drawing.Rectangle(0,0,136,54));
e.SetFont(0);
e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(1.0f, 1.0f, 1.0f, 0.85f);
e.FontColor.States[(int)ControlState.MouseOver] = BlackColorValue;
// Assign the element
SetDefaultElement(ControlType.Button, Button.ButtonLayer, e);
//-------------------------------------
// Button - Fill Layer
//-------------------------------------
e.SetTexture(0, new System.Drawing.Rectangle(136,0,136,54), TransparentWhite);
e.TextureColor.States[(int)ControlState.MouseOver] = new ColorValue(1.0f, 1.0f, 1.0f, 0.6f);
e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0, 0.25f);
e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.05f);
// Assign the element
SetDefaultElement(ControlType.Button, Button.FillLayer, e);
囚衣当然分上衣和裤子了,当然女囚犯要穿连衣裙也不是不可以……或者还有人喜欢戴帽子……
可以看到整个Button分为两个Element:Button本身和它的Fill Layer(Control、Element等之间的关系下篇文章再说吧)。首先,创建一个新的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相应的位置备用:
/// 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通过Dialog的AddControl方法添加到Dialog中
咦?这么快就拉来一车囚犯!?老大,我会忙不过来的!来来,排队登记!
首先,控件通过如下语句从parentDialog中创建:
Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
我们来看看Dialog内部是如何添加它的:
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方法:
/// 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方法将指定Control的Element索引值赋值为defaultElementList中存储的相应的ElementHolder中的Element值
那么Control是如何被初始化的呢?
嗯,你今天是囚犯3527了,看看仓库里面有没有你能穿的囚衣。这个尺寸的囚衣适合你啦,上衣和裤子都合适,还附送一顶帽子……喂!别把裤子套头上啦。
/// 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.Dialog的OnRender方法调用Control的Render方法
囚衣穿好了没?今天是监狱开放日!顺便展示一下我们的新款囚衣。
报告,广场太小了,站不下这么多人……
那……那改天再拉你们出去游街吧……
在Dialog的OnRender中有如下的渲染Control的代码:
// 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中各个Control的Render方法。
7. Control的Render方法调用Dialog的DrawSprite方法将自己的Element逐个显示出来
囚犯:唉……我没自由、失自由……出去放风都要人看着,还得穿上囚衣……
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 饰 囚犯