这些天项目中需要用到自动适应文本大小的文本框控件。
本以为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
{
    ///
    /// 锁定的位置
    ///

    public enum LockPosition
    {
        LockTopLeft,
        LockTopHCenter,
        LockTopRight,
        LockVCenterRight,
        LockBottomRight,
        LockBottomHCenter,
        LockBottomLeft,
        LockVCenterLeft,
        LockVCenterHCenter
    }
    ///
    /// 自动适应文本大小的文本框控件
    /// 继承自TextBox
    /// 2007 9 30 bug:键盘输入时,并不能保持中心点不变,原因:每次变化去求前一次的
    /// 保持的位置,长久下来累计误差比较大,因为中间除2了,可能会舍入。修改为保存好不变的位置
    ///

    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;
        }
        ///
        /// 不变化的位置坐标
        ///

        private Point m_unchangeLocation;
        bool m_unchangleLocationInit;//是否已经初始化m_unchangeLocation
        ///
        /// 调整大小
        ///

        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();
        }
        ///
        /// 重绘边框
        ///

        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);
        }
        ///
        /// 得到合适的客户区大小
        ///

        ///
        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;
        }
        ///
        /// 当文本改变时
        ///

        ///
        protected override void OnTextChanged(EventArgs e)
        {
            //call base
            base.OnTextChanged(e);
            //set auto size
            AdjustSize();
        }
        ///
        /// 字体变化
        ///

        ///
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            AdjustSize();
        }
        ///
        /// 得到合适的尺寸
        ///

        ///
        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();
        }
        ///
        /// 得到边框宽度
        ///

        ///
        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
        ///
        /// 重载wndproc
        ///

        ///
        protected override void WndProc(ref   Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_PAINT)
                DrawFixedSingle();
            if (m.Msg == WM_NCPAINT)
                DrawFixed3D();
        }
        ///
        /// 绘制非客户区边框
        ///

        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();
            }
        }
        ///
        /// 绘制客户区边框
        ///

        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);  
        }
        ///
        /// 覆盖Location
        ///

        public new Point Location
        {
            get
            {
                return base.Location;
            }
            set
            {
                base.Location = value;
                UpdateunchangeLocation();
            }
        }
    }
}
 
有兴趣下载的: