zoukankan      html  css  js  c++  java
  • 如何创建一个自定义组合框从零开始

    介绍 几个星期前,我花了很多时间在网上搜索一个完全定制的组合框,我可以在我的应用程序中使用。我没有找到好看的免费的。我并不假装没有这样的控制创建,但我的搜索错误激励我自己建立一个。下面我包含的代码示例与我的应用程序中的并不完全相同,但这是介绍创建自定义combobox的好方法。 它是如何工作的? 如果我们打开MSDN并稍微搜索一下,我们会发现。net组合框扩展了ListControl类。基本上,ComboBox由一个文本框和一个列表框组成,列表框以弹出窗口的形式出现在屏幕上。 因此,我所做的只是在。net 2.0中实现ListControl类并添加一个textbox和一个带有适当弹出控件的listbox。 下面是类模式: 有一些方法和属性需要被重写、重载或取消,以便为combobox实现适当的功能。我不知道从哪里开始,但最好展示一下我的工作的基本章节,其余的可以在附加的源代码中看到。 让我们从构造函数开始: 隐藏,收缩,复制Code

    #region Constructor
    public BNComboBox()
    {
        //preparing the basic control behavior
        SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        SetStyle(ControlStyles.ContainerControl, true);
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        SetStyle(ControlStyles.ResizeRedraw, true);
        SetStyle(ControlStyles.Selectable, true);
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        SetStyle(ControlStyles.UserMouse, true);
        SetStyle(ControlStyles.UserPaint, true);
        SetStyle(ControlStyles.Selectable, true);
    
        //setting some variables
        base.BackColor = Color.Transparent;
        _radius.BottomLeft = 2;
        _radius.BottomRight = 2;
        _radius.TopLeft = 2;
        _radius.TopRight = 6;
    
        this.Height = 21;
        this.Width = 95;
    
        //adjusting the component controls
        this.SuspendLayout();
        _textBox = new TextBox();
        _textBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
        _textBox.Location = new System.Drawing.Point(3, 4);
        _textBox.Size = new System.Drawing.Size(60, 13);
        _textBox.TabIndex = 0;
        _textBox.WordWrap = false;
        _textBox.Margin = new Padding(0);
        _textBox.Padding = new Padding(0);
        _textBox.TextAlign = HorizontalAlignment.Left;
        this.Controls.Add(_textBox);
        this.ResumeLayout(false);
    
        //very important function that aligns the nested controls
        AdjustControls();
    
        //adjusting the component controls
        _listBox = new ListBox();
        _listBox.IntegralHeight = true;
        _listBox.BorderStyle = BorderStyle.FixedSingle;
        _listBox.SelectionMode = SelectionMode.One;
        _listBox.BindingContext = new BindingContext();
    
        _controlHost = new ToolStripControlHost(_listBox);
        _controlHost.Padding = new Padding(0);
        _controlHost.Margin = new Padding(0);
        _controlHost.AutoSize = false;
    
        _popupControl = new ToolStripDropDown();
        _popupControl.Padding = new Padding(0);
        _popupControl.Margin = new Padding(0);
        _popupControl.AutoSize = true;
        _popupControl.DropShadowEnabled = false;
        _popupControl.Items.Add(_controlHost);
    
        _dropDownWidth = this.Width;
    
        //exposing the listbox event handlers 
        //to the outer control - the combobox
        _listBox.MeasureItem += 
            new MeasureItemEventHandler(_listBox_MeasureItem);
        _listBox.DrawItem += new DrawItemEventHandler(_listBox_DrawItem);
        _listBox.MouseClick += new MouseEventHandler(_listBox_MouseClick);
        _listBox.MouseMove += new MouseEventHandler(_listBox_MouseMove);
    
        _popupControl.Closed += 
            new ToolStripDropDownClosedEventHandler(_popupControl_Closed);
    
        _textBox.Resize += new EventHandler(_textBox_Resize);
        _textBox.TextChanged += new EventHandler(_textBox_TextChanged);
    }
    
    #endregion

    您可以检查源中的控件对齐功能。 为了在combobox上捕获某些事件,我声明了以下事件处理程序和委托: 隐藏,复制Code

    public delegate void BNDroppedDownEventHandler
        (object sender, EventArgs e);
    public delegate void BNDrawItemEventHandler
        (object sender, DrawItemEventArgs e);
    public delegate void BNMeasureItemEventHandler
        (object sender, MeasureItemEventArgs e);
        
    #region Delegates
    
    [Category("Behavior"), 
        Description("Occurs when IsDroppedDown changes to True.")]
    public event BNDroppedDownEventHandler DroppedDown;
    
    [Category("Behavior"), 
        Description("Occurs when the SelectedIndex property changes.")]
    public event EventHandler SelectedIndexChanged;
    
    [Category("Behavior"), 
        Description("Occurs when an item/area needs to be painted.")]
    public event BNDrawItemEventHandler DrawItem;
    
    [Category("Behavior"), 
        Description("Occurs when an item's height needs to be calculated.")]
    public event BNMeasureItemEventHandler MeasureItem;
    
    #endregion

    这是我如何调用DrawItem事件,例如: 隐藏,复制Code

    void _listBox_DrawItem(object sender, DrawItemEventArgs e)
    {
        if (e.Index >= 0)
        {
            if (DrawItem != null)
            {
                DrawItem(this, e);
            }
        }
    }

    绘画的控制 除了在构造函数中更改控件的样式外,还有许多其他属性和方法需要开发。 隐藏,复制Code

    public new Color BackColor
    {
        get { return _backColor; }
        set 
        { 
            this._backColor = value;
            _textBox.BackColor = value;
            Invalidate(true);
        }
    }

    正如您在构造函数中看到的,我们将BackColor属性设置为Transparent,并且不再触及它。相反,我使用一个局部变量,并重载基。在我们的例子中是listcontrol。BackColor。 我还添加了四个颜色属性和一个半径变量,可以在绘图代码中使用,以获得更好的外观和感觉。接下来,我们必须添加一些鼠标功能,如:处理鼠标的上、下、滚轮、进入、离开等。因此,当接收焦点、鼠标悬停或单击时,组合框可以改变其视图。 最后,只画combobox的部分: 隐藏,收缩,复制Code

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    
        //content border
        Rectangle rectCont = rectContent;
        rectCont.X += 1;
        rectCont.Y += 1;
        rectCont.Width -= 3;
        rectCont.Height -= 3;
        GraphicsPath pathContentBorder = 
            CreateRoundRectangle(rectCont, Radius.TopLeft, Radius.TopRight, 
                Radius.BottomRight, Radius.BottomLeft);
    
        //button border
        Rectangle rectButton = rectBtn;
        rectButton.X += 1;
        rectButton.Y += 1;
        rectButton.Width -= 3;
        rectButton.Height -= 3;
        GraphicsPath pathBtnBorder = 
            CreateRoundRectangle(rectButton, 0, 
                Radius.TopRight, Radius.BottomRight, 0);
    
        //outer border
        Rectangle rectOuter = rectContent;
        rectOuter.Width -= 1;
        rectOuter.Height -= 1;
        GraphicsPath pathOuterBorder = 
            CreateRoundRectangle(rectOuter, Radius.TopLeft, 
                Radius.TopRight, Radius.BottomRight,
                Radius.BottomLeft);
    
        //inner border
        Rectangle rectInner = rectContent;
        rectInner.X += 1;
        rectInner.Y += 1;
        rectInner.Width -= 3;
        rectInner.Height -= 3;
        GraphicsPath pathInnerBorder = 
            CreateRoundRectangle(rectInner, Radius.TopLeft, 
                Radius.TopRight, Radius.BottomRight,
                Radius.BottomLeft);
    
        //brushes and pens
        Brush brInnerBrush = new LinearGradientBrush(
            new Rectangle(rectInner.X,rectInner.Y,rectInner.Width,
                rectInner.Height+1), 
            (hovered || IsDroppedDown || ContainsFocus)?Color4:Color2, 
                Color.Transparent,
                LinearGradientMode.Vertical);
        Brush brBackground;
        if (this.DropDownStyle == ComboBoxStyle.DropDownList)
        {
            brBackground = new LinearGradientBrush(pathInnerBorder.GetBounds(), 
                Color.FromArgb(IsDroppedDown ? 100 : 255, Color.White), 
                Color.FromArgb(IsDroppedDown?255:100, BackColor),
                LinearGradientMode.Vertical);
        }
        else
        {
            brBackground = new SolidBrush(BackColor);
        }
        Pen penOuterBorder = new Pen(Color1, 0);
        Pen penInnerBorder = new Pen(brInnerBrush, 0);
        LinearGradientBrush brButtonLeft = 
            new LinearGradientBrush(rectBtn, Color1, Color2, 
                LinearGradientMode.Vertical);
        ColorBlend blend = new ColorBlend();
        blend.Colors = new Color[] 
            { Color.Transparent, Color2, Color.Transparent };
        blend.Positions = new float[] { 0.0f, 0.5f, 1.0f};
        brButtonLeft.InterpolationColors = blend;
        Pen penLeftButton = new Pen(brButtonLeft, 0);
        Brush brButton = 
            new LinearGradientBrush(pathBtnBorder.GetBounds(),
            Color.FromArgb(100, IsDroppedDown? Color2:Color.White),
                Color.FromArgb(100, IsDroppedDown ? Color.White : Color2),
                LinearGradientMode.Vertical);
    
        //draw
        e.Graphics.FillPath(brBackground, pathContentBorder);
        if (DropDownStyle != ComboBoxStyle.DropDownList)
        {
            e.Graphics.FillPath(brButton, pathBtnBorder);
        }
        e.Graphics.DrawPath(penOuterBorder, pathOuterBorder);
        e.Graphics.DrawPath(penInnerBorder, pathInnerBorder);
    
        e.Graphics.DrawLine(penLeftButton, rectBtn.Left + 1, 
            rectInner.Top+1, rectBtn.Left + 1, rectInner.Bottom-1);    
    
        //Glimph
        Rectangle rectGlimph = rectButton;
        rectButton.Width -= 4;
        e.Graphics.TranslateTransform(rectGlimph.Left + 
            rectGlimph.Width / 2.0f, 
            rectGlimph.Top + rectGlimph.Height / 2.0f);
        GraphicsPath path = new GraphicsPath();
        PointF[] points = new PointF[3];
        points[0] = new PointF(-6 / 2.0f, -3 / 2.0f);
        points[1] = new PointF(6 / 2.0f, -3 / 2.0f);
        points[2] = new PointF(0, 6 / 2.0f);
        path.AddLine(points[0], points[1]);
        path.AddLine(points[1], points[2]);
        path.CloseFigure();
        e.Graphics.RotateTransform(0);
    
        SolidBrush br = new SolidBrush(Enabled?Color.Gray:Color.Gainsboro);
        e.Graphics.FillPath(br, path);
        e.Graphics.ResetTransform();
        br.Dispose();
        path.Dispose();
    
        //text
        if (DropDownStyle == ComboBoxStyle.DropDownList)
        {
            StringFormat sf  = new StringFormat(StringFormatFlags.NoWrap);
            sf.Alignment = StringAlignment.Near;
    
            Rectangle rectText = _textBox.Bounds;
            rectText.Offset(-3, 0);
    
            SolidBrush foreBrush = new SolidBrush(ForeColor);
            if (Enabled)
            {
                e.Graphics.DrawString(_textBox.Text, this.Font, 
                    foreBrush, rectText.Location);
            }
            else
            {
                ControlPaint.DrawStringDisabled(e.Graphics, _textBox.Text, 
                    Font, BackColor, rectText, sf);
            }
        }
        /*
        Dim foreBrush As SolidBrush = New SolidBrush(color)
        If (enabled) Then
            g.DrawString(text, font, foreBrush, rect, sf)
        Else
            ControlPaint.DrawStringDisabled(g, text, font, backColor, _
                 rect, sf)
        End If
        foreBrush.Dispose()*/
    
        pathContentBorder.Dispose();
        pathOuterBorder.Dispose();
        pathInnerBorder.Dispose();
        pathBtnBorder.Dispose();
    
        penOuterBorder.Dispose();
        penInnerBorder.Dispose();
        penLeftButton.Dispose();
    
        brBackground.Dispose();
        brInnerBrush.Dispose();
        brButtonLeft.Dispose();
        brButton.Dispose();
    }

    下拉 另一件重要的事情是下拉函数。控制弹出列表框的基本属性是IsDroppedDown。 隐藏,收缩,复制Code

    public bool IsDroppedDown
    {
        get { return _isDroppedDown; }
        set 
        {
            if (_isDroppedDown == true && value == false )
            {
                if (_popupControl.IsDropDown)
                {
                    _popupControl.Close();
                }
            }
    
            _isDroppedDown = value;
    
            if (_isDroppedDown)
            {
                _controlHost.Control.Width = _dropDownWidth;
    
                _listBox.Refresh();
    
                if (_listBox.Items.Count > 0) 
                {
                    int h = 0;
                    int i = 0;
                    int maxItemHeight = 0;
                    int highestItemHeight = 0;
                    foreach(object item in _listBox.Items)
                    {
                        int itHeight = _listBox.GetItemHeight(i);
                        if (highestItemHeight < itHeight) 
                        {
                            highestItemHeight = itHeight;
                        }
                        h = h + itHeight;
                        if (i <= (_maxDropDownItems - 1)) 
                        {
                            maxItemHeight = h;
                        }
                        i = i + 1;
                    }
    
                    if (maxItemHeight > _dropDownHeight)
                        _listBox.Height = _dropDownHeight + 3;
                    else
                    {
                        if (maxItemHeight > highestItemHeight )
                            _listBox.Height = maxItemHeight + 3;
                        else
                            _listBox.Height = highestItemHeight + 3;
                    }
                }
                else
                {
                    _listBox.Height = 15;
                }
    
                _popupControl.Show(this, CalculateDropPosition(), 
                    ToolStripDropDownDirection.BelowRight);
            }
    
            Invalidate();
            if (_isDroppedDown)
                OnDroppedDown(this, EventArgs.Empty);
        }
    }

    还有其他属性和方法需要重写。可以在附件的代码中看到。 使用的代码 使用代码就像使用基本的ComboBox控件一样简单。有一些属性没有实现,比如在最初的ComboBox控件中,但是我把它留给以后的开发。 历史 2008年11月13日:初版 本文转载于:http://www.diyabc.com/frontweb/news277.html

  • 相关阅读:
    C++语言的url encode 和decode
    ICE实现服务器客户端
    ICE:slice语言常识整理
    SSH框架总结(框架分析+环境搭建+实例源代码下载)
    MyEclipse下XFire开发Webservice实例
    关于hashCode与equals
    xcode 4.5 new feature __ ios6 新特性
    js中substr与substring的差别
    MP算法和OMP算法及其思想
    android传感器;摇一摇抽签功能
  • 原文地址:https://www.cnblogs.com/Dincat/p/13437379.html
Copyright © 2011-2022 走看看