日期:2014-05-20  浏览次数:21026 次

升星了,散分庆祝一下。附一个类Iphone闹钟的时间选择控件
终于脱掉了5个小裤衩。。。。

前一段时间有人问过如何弄一个类似Iphone的list control,这两天写了一个,贴出来分享一下,不过功能还未完善。

C# code

    public partial class CustomListControl : Control
    {
        public CustomListControl()
        {
            InitializeComponent();
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(
                ControlStyles.AllPaintingInWmPaint | 
                ControlStyles.OptimizedDoubleBuffer | 
                ControlStyles.UserPaint, 
                true
                );
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);

            // Draw background
            Rectangle clientRect = new Rectangle(
                kBorderWidth, 
                kBorderWidth, 
                this.ClientRectangle.Width - 2 * kBorderWidth, 
                this.ClientRectangle.Height - 2 * kBorderWidth
                );

            using (LinearGradientBrush b = new LinearGradientBrush(
                clientRect,
                Color.Black,
                Color.White,
                90f)
                )
            {
                Blend blend = new Blend();
                blend.Positions = new float[] { 0.0f, 0.04f, 0.08f, 0.12f, 0.15f, 0.5f, 0.85f, 0.88f, 0.92f, 0.96f, 1f };
                blend.Factors = new float[] {   .2f,  .4f,  0.6f,  0.8f, 0.85f,  0.95f,  .85f,   .8f,  .6f,   .4f,  .2f };
                b.Blend = blend;
                pe.Graphics.FillRectangle(b, clientRect);
            }

            // Draw border
            using (Pen p = new Pen(Color.FromArgb(127, 127, 127)))
            {
                p.Width = kBorderWidth;
                pe.Graphics.DrawRectangle(
                    p, 
                    new Rectangle(
                        kBorderWidth / 2,
                        kBorderWidth / 2, 
                        this.Width - kBorderWidth, 
                        this.Height - kBorderWidth
                        )
                    );
            }

            
            // Draw selected focus
            Rectangle selectedBound = new Rectangle(
                        this.ClientRectangle.X,
                        this.ClientRectangle.Y + ((Int32)m_DisplayItemCount / 2) * this.ClientRectangle.Height / (Int32)m_DisplayItemCount,
                        this.ClientRectangle.Width,
                        this.ClientRectangle.Height / (Int32)m_DisplayItemCount
                        );
            using (Pen p = new Pen(Color.FromArgb(100, 100, 100, 100)))
            {
                pe.Graphics.DrawLine(
                    p, 
                    new Point(selectedBound.X, selectedBound.Y), 
                    new Point(selectedBound.X + selectedBound.Width, selectedBound.Y)
                    );
            }
            using (Pen p = new Pen(Color.FromArgb(100, 250, 250, 250)))
            {
                pe.Graphics.DrawLine(
                    p, 
                    new Point(selectedBound.X, selectedBound.Y + 1), 
                    new Point(selectedBound.X + selectedBound.Width, selectedBound.Y + 1)
                    );
            }

            using (Pen p = new Pen(Color.FromArgb(100, 100, 100, 100)))
            {
                pe.Graphics.DrawLine(
                    p, 
                    new Point(selectedBound.X, selectedBound.Y + selectedBound.Height - 2), 
                    new Point(selectedBound.X + selectedBound.Width, selectedBound.Y + selectedBound.Height - 2)
                    );
            }
            using (Pen p = new Pen(Color.FromArgb(100, 250, 250, 250)))
            {
                pe.Graphics.DrawLine(
                    p, 
                    new Point(selectedBound.X, selectedBound.Y + selectedBound.Height - 1), 
                    new Point(selectedBound.X + selectedBound.Width, selectedBound.Y + selectedBound.Height - 1)
                    );
            }

            using (Brush b = new SolidBrush(Color.FromArgb(100, 255, 255, 255)))
            {
                pe.Graphics.FillRectangle(
                    b, 
                    new Rectangle(
                        selectedBound.X, 
                        selectedBound.Y + 2, 
                        selectedBound.Width, 
                        selectedBound.Height / 2 - 2
                        )
                    );
            }

            using (Brush b = new SolidBrush(Color.FromArgb(100, 180, 180, 180)))
            {
                pe.Graphics.FillRectangle(
                    b, 
                    new Rectangle(
                        selectedBound.X, 
                        selectedBound.Y + selectedBound.Height / 2 + 1, 
                        selectedBound.Width, 
                        selectedBound.Height / 2 - 2
                        )
                    );
            }

            // Draw display items
            if (m_Items.Count == 0)
                return;

            using (Brush b = new SolidBrush(this.ForeColor))
            {
                for (Int32 i = 0; i < (Int32)m_DisplayItemCount; i++)
                {
                    Rectangle bound = new Rectangle(
                        clientRect.X,
                        clientRect.Y + i * clientRect.Height / (Int32)m_DisplayItemCount,
                        clientRect.Width,
                        clientRect.Height / (Int32)m_DisplayItemCount
                        );
                    Int32 index = m_CurrentIndex + i - (Int32)m_DisplayItemCount / 2;
                    if (index < 0)
                        index += m_Items.Count;
                    if (index >= m_Items.Count)
                        index %= m_Items.Count;
                    String item = m_Items[index];
                    using (StringFormat sf = new StringFormat())
                    {
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Center;
                        pe.Graphics.DrawString(item, this.Font, b, bound, sf);
                    }
                }

            }
        }

        protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
        {
            base.OnPreviewKeyDown(e);
            switch (e.KeyCode)
            {
                case Keys.Up:
                    m_CurrentIndex--;
                    if (m_CurrentIndex < 0)
                        m_CurrentIndex += m_Items.Count;
                    this.Invalidate();
                    break;
                case Keys.Down:
                    m_CurrentIndex++;
                    if (m_CurrentIndex >= m_Items.Count)
                        m_CurrentIndex %= m_Items.Count;
                    this.Invalidate();
                    break;
                default:
                    break;
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            m_CurrentIndex -= e.Delta / 120;
            NormalizeCurrentIndex();
            this.Invalidate();
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            Int32 delta = e.Y / (this.ClientRectangle.Height / (Int32)m_DisplayItemCount);
            m_CurrentIndex += delta - 2;
            NormalizeCurrentIndex();
            this.Invalidate();
        }

        [DefaultValue(0)]
        private Int32 CurrentIndex
        {
            get { return m_CurrentIndex; }
            set { m_CurrentIndex = value; }
        }

        public List<String> Items
        {
            get { return m_Items; }
        }

        [DefaultValue(DisplayItemCountEnum.Normal)]
        public DisplayItemCountEnum DisplayItemCount
        {
            get { return m_DisplayItemCount; }
            set { m_DisplayItemCount = value; }
        }

        private void NormalizeCurrentIndex()
        {
            if (m_CurrentIndex >= m_Items.Count)
                m_CurrentIndex %= m_Items.Count;
            if (m_CurrentIndex < 0)
                m_CurrentIndex += m_Items.Count;
        }

        private List<String> m_Items = new List<String>();
        private Int32 m_CurrentIndex;
        private DisplayItemCountEnum m_DisplayItemCount = DisplayItemCountEnum.Normal;
        private const Int32 kBorderWidth = 3;

        public enum DisplayItemCountEnum
        {
            Less = 3,
            Normal = 5,
            More = 7
        }
    }