自動適應文本內容的文本框控件(winform)

這些天項目中需要用到自動適應文本大小的文本框控件。
本以爲Graphics.MeasureString可以獲得文字的範圍,但是怎麼弄
也和textbox的大小不一致,尤其是行數多了的時候。
網上估計有些兄弟也有這方面的問題。
 
後來通過看Textbox的源碼,發現用TextRenderer.MeasureText可以完美獲得和TextBox一樣的大小。故實現了以下控件。
有興趣看代碼的,代碼copy如下:
2007 9 30 使用的時候發現了bug:鍵盤輸入時,並不能保持中心點不變,原因:每次變化去求前一次的保持的位置,長久下來累計誤差比較大,因爲中間除2了,可能會舍入。修改爲保存好不變的位置
修改後代碼如下:
 
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Runtime.InteropServices;
using System.Drawing;
namespace Hob.Toolbox.Controls
{
    /// <summary>
    /// 鎖定的位置
    /// </summary>
    public enum LockPosition
    {
        LockTopLeft,
        LockTopHCenter,
        LockTopRight,
        LockVCenterRight,
        LockBottomRight,
        LockBottomHCenter,
        LockBottomLeft,
        LockVCenterLeft,
        LockVCenterHCenter
    }
    /// <summary>
    /// 自動適應文本大小的文本框控件
    /// 繼承自TextBox
    /// 2007 9 30 bug:鍵盤輸入時,並不能保持中心點不變,原因:每次變化去求前一次的
    /// 保持的位置,長久下來累計誤差比較大,因爲中間除2了,可能會舍入。修改爲保存好不變的位置
    /// </summary>
    public class AutoSizeTextBox : TextBox
    {
        public AutoSizeTextBox()
        {
            //默認多行
            base.Multiline = true;
            base.WordWrap = false;
            base.TextAlign = HorizontalAlignment.Center;
            base.BorderStyle = BorderStyle.FixedSingle;
            m_LockPosition = LockPosition.LockTopLeft;
            m_FrameColor = Color.Gray;
            m_unchangleLocationInit = false;
        }
        /// <summary>
        /// 不變化的位置座標
        /// </summary>
        private Point m_unchangeLocation;
        bool m_unchangleLocationInit;//是否已經初始化m_unchangeLocation
        /// <summary>
        /// 調整大小
        /// </summary>
        private void AdjustSize()
        {
            //調整大小
            ClientSize = GetRightClientSize();
            if (m_unchangleLocationInit)
            {
                switch (m_LockPosition)//保持位置
                {
                    case LockPosition.LockTopLeft:
                        Location = m_unchangeLocation;
                        break;
                    case LockPosition.LockTopHCenter:
                        Location = new Point(m_unchangeLocation.X - Size.Width / 2, m_unchangeLocation.Y);
                        break;
                    case LockPosition.LockTopRight:
                        Location = new Point(m_unchangeLocation.X - Size.Width, m_unchangeLocation.Y);
                        break;
                    case LockPosition.LockVCenterRight:
                        Location = new Point(m_unchangeLocation.X - Size.Width, m_unchangeLocation.Y - Size.Height / 2);
                        break;
                    case LockPosition.LockBottomRight:
                        Location = new Point(m_unchangeLocation.X - Size.Width, m_unchangeLocation.Y - Size.Height);
                        break;
                    case LockPosition.LockBottomHCenter:
                        Location = new Point(m_unchangeLocation.X - Size.Width / 2, m_unchangeLocation.Y - Size.Height);
                        break;
                    case LockPosition.LockBottomLeft:
                        Location = new Point(m_unchangeLocation.X, m_unchangeLocation.Y - Size.Height);
                        break;
                    case LockPosition.LockVCenterLeft:
                        Location = new Point(m_unchangeLocation.X, m_unchangeLocation.Y - Size.Height / 2);
                        break;
                    case LockPosition.LockVCenterHCenter:
                        Location = new Point(m_unchangeLocation.X - Size.Width / 2, m_unchangeLocation.Y - Size.Height / 2);
                        break;
                }
            }
           
            InvalidateFrame();
        }
        /// <summary>
        /// 重繪邊框
        /// </summary>
        private void InvalidateFrame()
        {
            if (BorderStyle == BorderStyle.Fixed3D)
                SetWindowPos(Handle, (IntPtr)0, 0, 0, 0, 0,
                 SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
        }
        /// <summary>
        /// 得到合適的客戶區大小
        /// </summary>
        /// <returns></returns>
        private Size GetRightClientSize()
        {
            Size size = GetRightTextSize();
            int borderwidth = GetBorderWidth();
            size.Width += borderwidth * 2;
            size.Height += borderwidth * 2;
            return size;
        }
        private Size GetRightSize()
        {
            Size size = GetRightClientSize();
            int borderwidth = GetBorderWidth();
            size.Width += borderwidth * 2;
            size.Height += borderwidth * 2;
            return size;
        }
        /// <summary>
        /// 當文本改變時
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTextChanged(EventArgs e)
        {
            //call base
            base.OnTextChanged(e);
            //set auto size
            AdjustSize();
        }
        /// <summary>
        /// 字體變化
        /// </summary>
        /// <param name="e"></param>
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            AdjustSize();
        }
        /// <summary>
        /// 得到合適的尺寸
        /// </summary>
        /// <returns></returns>
        private Size GetRightTextSize()
        {
            String str = Text;
            int len = str.Length;
            if (len<2) str = "tt";//至少兩個寬度
            int count = Lines.Length;
            if (count >= 1)
                if (Lines[count - 1] == "")
                    str += "tt";
            Size size = TextRenderer.MeasureText(str, Font);
            return size;
        }
        //border改變
        protected override void OnBorderStyleChanged(EventArgs e)
        {
            base.OnBorderStyleChanged(e);
            AdjustSize();
        }
        /// <summary>
        /// 得到邊框寬度
        /// </summary>
        /// <returns></returns>
        private int GetBorderWidth()
        {
            if (BorderStyle == BorderStyle.Fixed3D)
                return 2;
            else if (BorderStyle == BorderStyle.FixedSingle)
                return 1;
            else //none
                return 0;
        }
        //隱藏Multiline
        [Browsable(false)]
        public override bool Multiline
        {
            get
            {
                return base.Multiline;
            }
            set
            {
                base.Multiline = value;
            }
        }
        //隱藏WordWrap
        [Browsable(false)]
        public new bool WordWrap
        {
            get
            {
                return base.WordWrap;
            }
            set
            {
                base.WordWrap = value;
            }
        }
        [DefaultValue(HorizontalAlignment.Center)]//默認值設爲Center,並且構造函數爲center
        public new HorizontalAlignment TextAlign
        {
            get
            {
                return base.TextAlign;
            }
            set
            {
                base.TextAlign = value;
            }
        }
        [DefaultValue(BorderStyle.FixedSingle)]
        public new BorderStyle BorderStyle
        {
            get
            {
                return base.BorderStyle;
            }
            set
            {
                base.BorderStyle = value;
            }
        }
        private Color m_FrameColor;
        [Category("Appearance"), Description("邊框的顏色"), DefaultValue(typeof(Color), "Gray")]
        public Color FrameColor
        {
            get
            {
                return m_FrameColor;
            }
            set
            {
                m_FrameColor = value;
                InvalidateFrame();
            }
        }
        #region winodws api
        private const uint WM_NCPAINT = 0x0085;
        private const uint WM_PAINT = 0x000F;
        [DllImport("user32")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);
        [DllImport("user32")]
        private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
        private const int SWP_NOSIZE = 0x0001;
        private const int SWP_NOMOVE = 0x0002;
        private const int SWP_NOZORDER = 0x0004;
        private const int SWP_NOREDRAW = 0x0008;
        private const int SWP_NOACTIVATE = 0x0010;
        private const int SWP_FRAMECHANGED = 0x0020;  /* The frame changed: send WM_NCCALCSIZE */
        [DllImport("user32")]
        private static extern bool SetWindowPos(IntPtr hwnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
        #endregion
        /// <summary>
        /// 重載wndproc
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref   Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_PAINT)
                DrawFixedSingle();
            if (m.Msg == WM_NCPAINT)
                DrawFixed3D();
        }
        /// <summary>
        /// 繪製非客戶區邊框
        /// </summary>
        private void DrawFixed3D()
        {
            if (BorderStyle == BorderStyle.Fixed3D)
            {
                Pen pen = new Pen(this.m_FrameColor);
                IntPtr windc = GetWindowDC(Handle);
                Graphics borderG = Graphics.FromHdc(windc);
                borderG.DrawRectangle(pen, 0, 0, Size.Width - 1, Size.Height - 1);
                ReleaseDC(Handle, windc);
                borderG.Dispose();
                pen.Dispose();
            }
        }
        /// <summary>
        /// 繪製客戶區邊框
        /// </summary>
        private void DrawFixedSingle()
        {
            if (BorderStyle == BorderStyle.FixedSingle)
            {
                Pen pen = new Pen(this.m_FrameColor);
                Graphics dc = Graphics.FromHwnd(Handle);
                dc.DrawRectangle(pen, 0, 0, Size.Width - 1, Size.Height - 1);
                dc.Dispose();
                pen.Dispose();
            }
        }
        //鎖定的不變位置
        private LockPosition m_LockPosition;
        [Category("Layout"), Description("鎖定的不變位置"), DefaultValue(LockPosition.LockTopLeft)]
        public LockPosition TextLockPosition//修改名字爲TextLockPosition,使得InitializeComponent在text改變後加載TextLockPosition屬性
        {
            get
            {
                return m_LockPosition;
            }
            set
            {
                m_LockPosition = value;
                UpdateunchangeLocation();
            }
        }
        private void UpdateunchangeLocation()
        {
            //求不變的位置座標
            switch (m_LockPosition)//求保持的位置
            {
                case LockPosition.LockTopLeft:
                    m_unchangeLocation = Location;
                    break;
                case LockPosition.LockTopHCenter:
                    m_unchangeLocation = new Point(Location.X + Size.Width / 2, Location.Y);
                    break;
                case LockPosition.LockTopRight:
                    m_unchangeLocation = new Point(Location.X + Size.Width, Location.Y);
                    break;
                case LockPosition.LockVCenterRight:
                    m_unchangeLocation = new Point(Location.X + Size.Width, Location.Y + Size.Height / 2);
                    break;
                case LockPosition.LockBottomRight:
                    m_unchangeLocation = new Point(Location.X + Size.Width, Location.Y + Size.Height);
                    break;
                case LockPosition.LockBottomHCenter:
                    m_unchangeLocation = new Point(Location.X + Size.Width / 2, Location.Y + Size.Height);
                    break;
                case LockPosition.LockBottomLeft:
                    m_unchangeLocation = new Point(Location.X, Location.Y + Size.Height);
                    break;
                case LockPosition.LockVCenterLeft:
                    m_unchangeLocation = new Point(Location.X, Location.Y + Size.Height / 2);
                    break;
                case LockPosition.LockVCenterHCenter:
                    m_unchangeLocation = new Point(Location.X + Size.Width / 2, Location.Y + Size.Height / 2);
                    break;
            }
            m_unchangleLocationInit = true;
        }
        //重載禁止調整高度
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            Size size = GetRightSize();
            if (width != size.Width && ((specified & BoundsSpecified.Width) == BoundsSpecified.Width))
                width = size.Width;
            if (height != size.Height && ((specified & BoundsSpecified.Height) == BoundsSpecified.Height))
                height = size.Height;
            //call base
            base.SetBoundsCore(x, y, width, height, specified);  
        }
        /// <summary>
        /// 覆蓋Location
        /// </summary>
        public new Point Location
        {
            get
            {
                return base.Location;
            }
            set
            {
                base.Location = value;
                UpdateunchangeLocation();
            }
        }
    }
}
 
有興趣下載的:
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章