17.下拉列表框UIComboBox类

下拉列表框事实上就是一个文本框(目前还没有实现文本框,我认为编写文本框的难度应该是最大的,等以后必须用到时在攻克它吧,本例中的文本框是用一个带背景的文字代替的)、文本框右侧的复选按钮和列表框组合而成的控件,它要实现的主要功能如下:

具体代码代码如下:

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using StunEngine.Controllers;
using StunEngine.SceneManagement;

namespace StunEngine.SceneNodes.UI
{
    /// 
    /// 下列列表框
    /// 
    public class UIComboBox :UISceneNode 
    {
        //默认值
        private static readonly float DefaultComboBoxWidth = 160.0f;
        private static readonly float DefaultScrollBarWidth = 16.0f;
        private static readonly float DefaultListBoxHeight = 92.0f;
        private static readonly Rectangle DefaultTextBoxRect = new Rectangle(1, 1, 6, 6);
        private static readonly Rectangle DefaultButtonRectOrigin = new Rectangle(0, 16, 16, 16);
        private static readonly Rectangle DefaultButtonRectHighlight = new Rectangle(16, 16, 16, 16);        
        private static readonly Rectangle DefaultButtonRectChecked = new Rectangle(0, 48, 16, 16);
        private static readonly Rectangle DefaultButtonRectCheckedHighlight = new Rectangle(16, 48, 16, 16);        
        
        ///
        /// 下拉列表框右侧的复选框控件
        /// 
        UICheckBox button;

        ///
        /// 列表框控件
        /// 
        UIListBox listbox;

        ///
        /// 列表框高度,默认为92。它的宽度无需指定,等于下拉列表框宽度,默认为160。
        /// 
        private float listBoxHeight;

        ///
        /// 滚动条宽度,默认为16。
        /// 
        float scrollBarWidth;        

        ///
        /// 下拉列表框的宽度,默认为160。
        /// 
        float width;
        
        ///
        /// 文本框中的文字。
        /// 
        private string text;        

        ///
        /// 文字使用的字体。
        /// 
        private SpriteFont font;        

        ///
        /// 文本使用的颜色
        /// 
        private Color textColor;

        ///
        /// 文本框背景图像矩形
        /// 
        private Rectangle textBoxRect;        

        ///
        /// 按钮普通状态图像矩形
        /// 
        private Rectangle buttonRectOrigin;        

        ///
        /// 按钮高亮状态图像矩形
        /// 
        private Rectangle buttonRectHighlight;        

        ///
        /// 按钮选中状态图像矩形
        /// 
        private Rectangle buttonRectChecked;        

        ///
        /// 按钮选中时高亮状态图像矩形
        /// 
        private Rectangle buttonRectCheckedHighlight;        

        ///
        /// 当选中的文字项发生改变时引发的事件。
        /// 
        public event EventHandler SelectionChanged = null;
        
        ///
        /// 列表框是否处于打开状态。
        /// 
        bool justOpened = false;        
        
        ///
        /// 创建一个默认ComboBox,文字项数组为空。
        /// 
        /// 引擎
        /// 所属场景
        public UIComboBox(StunXnaGE engine, Scene setScene):this(engine ,setScene ,null)
        {
            
        }

        /// 
        /// 创建一个ComboBox,需要传递文字项数组
        /// 
        /// 引擎
        /// 所属场景
        /// 文字项数组
        public UIComboBox(StunXnaGE engine, Scene setScene,string [] setItems)
            : this(engine, setScene, Vector2.Zero, "Textures/UI/UITextBox", DefaultComboBoxWidth,DefaultListBoxHeight ,DefaultScrollBarWidth,engine.DefaultFont, Color.White,DefaultTextBoxRect ,DefaultButtonRectOrigin ,DefaultButtonRectHighlight ,DefaultButtonRectChecked ,DefaultButtonRectCheckedHighlight ,setItems)
        {

        }

        /// 
        /// 创建一个UIComboBox,内部方法,只能在引擎内部调用。
        /// 
        /// 引擎
        /// 所属场景
        /// 控件的2D屏幕位置
        /// 纹理名称
        /// 下拉列表框宽度
        /// 列表框高度
        /// 滚动条宽度
        /// 文字使用的字体
        /// 文字颜色
        /// 文本框图像矩形
        /// 按钮普通状态图像矩形
        /// 按钮高亮状态图像矩形
        /// 按钮选中状态图像矩形
        /// 按钮选中时高亮状态图像矩形
        /// 文字项数组
        internal UIComboBox(StunXnaGE engine, Scene setScene, Vector2 setPosition,string setTextureName,float setWidth,float setListBoxHeight,float setScrollBarWidth,SpriteFont setFont,Color setTextColor,Rectangle setTextBoxRect,Rectangle setButtonRectOrigin,Rectangle setButtonHighlight,Rectangle setButtonRectChecked,Rectangle setButtonRectCheckedHighlight,string [] setItems) : base(engine, setScene, setPosition, setTextureName) 
        {
            this.font =setFont ;
            this.textColor = setTextColor;
            this.width = setWidth;
            this.scrollBarWidth = setScrollBarWidth;
            this.listBoxHeight = setListBoxHeight;
            this.size=new Vector2 (width ,font .LineSpacing );

            this.textBoxRect =setTextBoxRect ;
            this.buttonRectOrigin = setButtonRectOrigin;
            this.buttonRectHighlight = setButtonHighlight;
            this.buttonRectChecked = setButtonRectChecked;
            this.buttonRectCheckedHighlight = setButtonRectCheckedHighlight;
           
            //初始化并添加一个下拉按钮,实际上是一个不含文字的复选框
            button = new UICheckBox(engine, setScene, new Vector2(position.X + size.X - size.Y, position.Y), "Textures/UI/UIScrollBar", new Vector2(size.Y, size.Y), null, engine.DefaultFont, Color.White, Color.White, buttonRectOrigin, buttonRectHighlight, buttonRectChecked, buttonRectCheckedHighlight);
            button.TabStop = false;
            button.CheckedChanged +=new EventHandler(button_CheckedChanged);
            this.scene.AddNode(button);

            //初始化并添加一个列表框
            if(setItems !=null)
                listbox = new UIListBox(engine ,setScene,setItems);
            else
                listbox = new UIListBox(engine, setScene);
            listbox.ChangeSelection +=new EventHandler(listbox_ChangeSelection);
            listbox .MouseClick +=new System.Windows.Forms.MouseEventHandler(listbox_MouseClick);
            listbox.TabStop = false;            
            this.scene.AddNode(listbox);
            
            //鼠标点击下拉列表框时控制列表框的可见与否,其实就是调用按钮的点击事件
            this.MouseClick += new System.Windows.Forms.MouseEventHandler(combo_MouseClick);
            
            //绘制下拉列表框
            Redraw();
        }        

        #region 属性
        
        /// 
        /// 获取或设置文本框中的文字
        /// 
        public string Text
        {
            get { return text; }
        }

        /// 
        /// 获取或设置文本使用的字体
        /// 
        public SpriteFont Font
        {
            get { return font; }
            set
            {
                font = value;
                listbox.Font = value;
            }
        }

        /// 
        /// 获取或设置文本使用的颜色
        /// 
        public Color TextColor
        {
            get { return textColor; }
            set { textColor = value; }
        }

        /// 
        /// 获取或设置文本框背景图像矩形
        /// 
        public Rectangle TextBoxRect
        {
            get { return textBoxRect; }
            set { textBoxRect = value; }
        }

        /// 
        /// 获取或设置按钮普通状态图像矩形
        /// 
        public Rectangle ButtonRectOrigin
        {
            get { return buttonRectOrigin; }
            set { buttonRectOrigin = value; }
        }

        /// 
        /// 获取或设置按钮高亮状态图像矩形
        /// 
        public Rectangle ButtonRectHighlight
        {
            get { return buttonRectHighlight; }
            set { buttonRectHighlight = value; }
        }

        /// 
        /// 获取或设置按钮选中状态图像矩形
        /// 
        public Rectangle ButtonRectChecked
        {
            get { return buttonRectChecked; }
            set { buttonRectChecked = value; }
        }

        /// 
        /// 获取或设置按钮选中时高亮状态图像矩形
        /// 
        public Rectangle ButtonRectCheckedHighlight
        {
            get { return buttonRectCheckedHighlight; }
            set { buttonRectCheckedHighlight = value; }
        }

        /// 
        /// 获取或设置滚动条宽度,默认为16。
        /// 
        public float ScrollBarWidth
        {
            get { return listbox.ScrollBarWidth;}
            set { listbox.ScrollBarWidth = value; }
        }

        /// 
        /// 获取或设置选中文字项的文字
        /// 
        public string SelectedItem
        {
            get
            {
                return listbox.SelectedItem;
            }
            set
            {
                listbox.SelectedItem = value;
                text = listbox.SelectedItem; 
            }
        }

        /// 
        /// 获取选中的文字项的索引
        /// 
        public int SelectedIndex
        {
            get { return listbox.SelectedIndex; }
            set
            {
                listbox.SelectedIndex = value;
                text = listbox[value];
            }
        }

        /// 
        /// 获取或设置列表框的文字项数组
        /// 
        public List Items { get { return listbox.Items; } set { listbox.Items = value; } }

        /// 
        /// 获取列表框是否被显示
        /// 
        public bool Opened { get { return listbox.IsVisible; } }

        #endregion

        #region 事件相关方法

        /// 
        /// 在文字项数组中添加一个数据项
        /// 
        public void AddItem(string item)
        {
            listbox.AddItem(item);
            if (!justOpened)
                listbox.IsVisible = false;
        }

        /// 
        /// 下列列表框位置改变时需要重新绘制。
        /// 
        protected override void OnLocationChanged()
        {
            Redraw();
            base.OnLocationChanged();
        }

        /// 
        /// 下列列表框大小改变时需要重新绘制。
        /// 
        protected override void OnSizeChanged()
        {
            Redraw();
            base.OnSizeChanged();
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            button.IsVisible = isVisible;
            if(justOpened )
                listbox.IsVisible =isVisible ;
        }

        /// 
        /// 重新绘制下列列表框。
        /// 
        private void Redraw()
        {
            this.size = new Vector2(size.X, font.LineSpacing);
            
            button.Position = new Vector2(position.X + size.X - size.Y, position.Y);

            listbox.Size = new Vector2(width, listBoxHeight);
            listbox.ScrollBarWidth = scrollBarWidth;            
            listbox.Position = new Vector2(position.X, position.Y + size.Y);
            listbox.Font = font;
            listbox.Size = new Vector2(size.X, listbox .Size .Y);
            if (!justOpened)
                listbox.IsVisible = false;
        }

        /// 
        /// 点击列表框关闭列表框
        /// 
        /// 
        /// 
        void listbox_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            listbox.IsVisible = false;
        }       

        /// 
        /// 将文本框中的文字设置为选中的文字项,如果选中的文字项发生变化则引发SelectionChanged事件。
        /// 
        /// 
        /// 
        void listbox_ChangeSelection(object sender, EventArgs e)
        {
            string previousItem = text;
            text = listbox.SelectedItem;

            if (text != previousItem && SelectionChanged != null)
                SelectionChanged(listbox.SelectedItem, null);
            Close();
        }        

        /// 
        /// 点击控件相当于点击右侧按钮
        /// 
        /// 
        /// 
        void combo_MouseClick(object sender, EventArgs e)
        {
            button.OnCheckedChanged(e);
        }

        /// 
        /// 点击按钮打开列表框
        /// 
        /// 
        /// 
        void button_CheckedChanged(object sender, EventArgs e)
        {
            if (isVisible)
            {
                if (!listbox.IsVisible)
                    Open();
                else
                    Close();
            }
        }

        /// 
        /// 打开列表框
        /// 
        private void Open()
        {
            justOpened = true;
            listbox.IsVisible = true;
        }

        /// 
        /// 关闭列表框
        /// 
        private void Close()
        {
            listbox.IsVisible = false;
            justOpened = false;
        }

        #endregion

        /// 
        /// 绘制控件
        /// 
        public override void Draw(GameTime gameTime, bool useReflection)
        {
            //获取图像淡入淡出的透明颜色
            alphaTextureColor = new Color(color, scene.TransitionAlpha);

            //绘制文本框背景
            StunXnaGE.SpriteBatch.Draw(material.Textures[0], new Rectangle((int)position.X, (int)(position.Y), (int)(size.X - size.Y), (int)size.Y), textBoxRect, alphaTextureColor, rotation, origin, spriteEffect, layerDepth);
            //绘制文本框上的文字
            if (text != null)
                StunXnaGE.SpriteBatch.DrawString(font, text, position, textColor);

        }

        #region 单元测试

#if DEBUG
        /// 
        /// 测试UIComboBox类
        /// 
        public static void TestUIComboBox()
        {
            UIComboBox comboBox = null;            

            TestGame.Start("测试UIComboBox类,可按空格,上下键,数字键12",
                delegate
                {
                    comboBox = new UIComboBox(TestGame.engine, TestGame.scene);
                    TestGame.scene.AddNode(comboBox);   
                    comboBox.AddItem("1");
                    comboBox.AddItem("2");
                    comboBox.AddItem("3");
                    comboBox.AddItem("4");
                    comboBox.AddItem("5");
                    comboBox.AddItem("6");
                    comboBox.Position = new Vector2(100, 150);
                    comboBox.SelectedIndex  =3;

                    //关闭相机控制器
                    TestGame.scene.fpsCamCtrl.Enabled = false;
                },
                delegate
                {
                    //按向下键移动控件
                    if (Input.KeyboardDownJustPressed)
                        comboBox.Position += new Vector2(5, 5);
                    //按向上键改变大小
                    if (Input.KeyboardUpJustPressed)
                        comboBox.Size += new Vector2(5, 5);
                    //按空格键测试isVisible属性
                    if (Input.KeyboardSpaceJustPressed)
                        comboBox.IsVisible = !comboBox.IsVisible;
                    //按数字1键新添数据项
                    if (Input.KeyboardKeyJustPressed(Keys.D1))
                        comboBox.AddItem("NewItem");
                    //按数字2键改变滚动条宽度
                    if (Input.KeyboardKeyJustPressed(Keys.D2))
                        comboBox.ScrollBarWidth += 2;
                });
        }
#endif
        #endregion

        
    }
} 

代码有点长,其实关键代码并不多,只是为了使用灵活,这个控件(其实前面的控件也是)提供了很多可以被用户改变的属性,希望看代码时别被这些东西所干扰。

单元测试截图如下:

单元测试截图

现在的UI类图如下:

类关系图

2D编程终于告一段落了,其实我更感兴趣的是3D,会在下一个教程开始展开。


发布时间:2010/2/25 下午12:58:42  阅读次数:7741

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号