重写Winform的Textbox单行模式下滚动条。

5 篇文章 0 订阅

C# Textbox,必须同时设置属性Multiline = True、ScrollBars=Horizontal、WordWrap=False才会显示出水平滚动条,且默认字体大小下,控件的Size.Height >= 33才能正常显示完全文本。这非常的丑陋!占空间!

想着能调节压缩一下滚动条的高度就好了,只是现实太残酷,滚动条没有高度属性可设置!!!

只能想办法重写Textbox了。折腾两天,各种百度,终于实现自己想要的结果。


 

1、新建自定义控件,改变继承自TextBox。

    public partial class TinyXScrollBarTextBox : TextBox

 2、在TinyXScrollBarTextBox的设计模式中,拖放两个panel作为滚动条和滑块。分别命名为:panelXScrollBar、panelXScrollSlider。

3、在InitializeComponent()函数中设置,this.Controls.Add(this.panelXScrollBar);this.panelXScrollBar.Controls.Add(this.panelXScrollSlider);

 4、初始化三个关键属性,

        public TinyXScrollBarTextBox()
        {
            InitializeComponent();
            base.Multiline = true;
            base.WordWrap = false;
            base.ScrollBars = ScrollBars.None;
        }

 并加入如下代码,屏蔽其修改:

        /// <summary>
        /// 屏蔽系统的滚动条设置。并显示为水平滚动,实际为 base.ScrollBars = ScrollBars.None;
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ScrollBars ScrollBars
        {
            get
            {
                return ScrollBars.Horizontal;
            }
            set
            {
                base.ScrollBars = ScrollBars.None;
            }
        }        
        /// <summary>
        /// 屏蔽系统的多行开关,实际为 base.Multiline = true;
        /// </summary>
        //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new bool Multiline
        {
            get
            {
                return true;
            }
            set
            {
                base.Multiline = true;
            }

        }
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new bool WordWrap
        {
            get
            {
                return false;
            }
            set
            {
                base.WordWrap = false;
            }
        }

 5、文本框文本发生变化时,过滤掉转行、回车(\r or \n)。并禁止输入回车键,使现为多行模式下表现得像单行模式。

        protected override void OnTextChanged(EventArgs e)
        {
            ClearRNChar();
            var w = panelXScrollBar.Width;
            textGdiWidth = TextRenderer.MeasureText(Text, Font).Width;
            if (textGdiWidth > w)
            {
                this.panelXScrollBar.Visible = true;

                var ws = panelXScrollBar.Width * 2 - textGdiWidth;
                ws = ws < 25 ? 25 : ws; //计算滑块的长度,并设置最小为25个像素。
                panelXScrollSlider.Width = ws;
                var sliderW = panelXScrollBar.Width - panelXScrollSlider.Width;

                int indexWidth = GetTextGdiWidthByIndex(SelectionStart);

                SliderLeft = (int)((indexWidth * 1.0) / textGdiWidth * sliderW);
            }
            else
            {
                panelXScrollBar.Visible = false;
                var start = SelectionStart;
                SelectionStart = 0;
                ScrollToCaret();
                SelectionStart = start;
            }
            base.OnTextChanged(e);
        }

        private void TinyXScrollBarTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            //屏蔽回车键
            if ((int)e.KeyCode == 13)
            {
                e.SuppressKeyPress = true;
            }
        }

6、滑块的滑动代码,这部分来源于网络,找不到来源了,也不难。

        private static bool IsMove = false;                 //标识 鼠标在滑块上的运动状态 初始为false
        private int X;                                      //定义一个变量 用于记录鼠标进入滑块中并按下时的位置
        private void panelXScrollSlider_MouseDown(object sender, MouseEventArgs e)          //鼠标对滑块的按下事件 
        {
            IsMove = true;                                                //标识鼠标开始移动  
            X = e.Location.X;                                              //鼠标的初始位置的X坐标
            panelXScrollSlider.BackColor = Color.FromArgb(200, 100, 100, 100); ;         //滑块颜色变为深一点的色
        }

        private void panelXScrollSlider_MouseMove(object sender, MouseEventArgs e)      //鼠标对滑块的 移动 事件
        {
            if (IsMove == true)                             //如果鼠标开始移动
            {

                if (panelXScrollSlider.Right >= this.Width)
                {
                    if ((e.Location.X - X) < 0)                     //如果 鼠标向左滑动  
                    {
                        panelXScrollSlider.Left += e.Location.X - X;         //将滑块的位置增加  增加的量是鼠标移动的距离
                    }
                    else                                                //如果鼠标向下移动
                    {
                        panelXScrollSlider.Left = this.Width - panelXScrollSlider.Width;         //滑块的位置始终为 滑条最底部的位置
                    }
                }
                else if (panelXScrollSlider.Left <= 0)
                {
                    if ((e.Location.X - X) > 0)
                    {
                        panelXScrollSlider.Left += e.Location.X - X;
                    }
                    else
                    {
                        panelXScrollSlider.Left = 0;
                    }
                }
                else
                {
                    panelXScrollSlider.Left += e.Location.X - X;
                }
            }

        }

        private void panelXScrollSlider_MouseUp(object sender, MouseEventArgs e)            //当鼠标松开时候 意味着 用户 不再需要滑动滑块
        {
            IsMove = false;                             //此时将标识变为false
            panelXScrollSlider.BackColor = Color.FromArgb(100, 100, 100, 100);       //颜色变为原来的暗色
            SliderLeft = panelXScrollSlider.Left;//通过设置触发内容的滚动。
        }

        private void panelXScrollSlider_MouseEnter(object sender, EventArgs e)
        {
            panelXScrollSlider.BackColor = Color.FromArgb(200, 100, 100, 100);
        }

        private void panelXScrollSlider_MouseLeave(object sender, EventArgs e)
        {
            panelXScrollSlider.BackColor = Color.FromArgb(100, 100, 100, 100);
        }

7、鼠标点滚动条的操作:在滑块的右侧点击,则向右滚动,反之亦然

        /// <summary>
        /// 在滑块的右侧点击,则向右滚动,反之亦然
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panelXScrollBar_MouseClick(object sender, MouseEventArgs e)
        {
            if (Text.Length == 0)
            {
                return;
            }
            int oldStart = SelectionStart;
            int oldSlectedLen = SelectionLength;

            var ns = 0;
            if (e.X > panelXScrollSlider.Right)
            {
                var rightindex = GetCharIndexFromPosition(new Point(this.panelXScrollBar.Right - 3, 1));
                ns = rightindex + 1;
                ns = ns > Text.Length - 1 ? Text.Length : ns;

            }
            else if (e.X < panelXScrollSlider.Left)
            {
                var leftindex = GetCharIndexFromPosition(new Point(3, 1));
                ns = leftindex - 1;
                ns = ns < 0 ? 0 : ns;

            }

            SelectionStart = ns;
            SelectionLength = 0;
            ScrollToCaret();
            var left = (int)((ns * 1.0 / Text.Length) * (panelXScrollBar.Width - panelXScrollSlider.Width));
            panelXScrollSlider.Left = left;
            SelectionStart = oldStart;
            SelectionLength = oldSlectedLen;
        }

8、滑块与光标的联动。这一块实现得不是丝滑,不过差不多就得了。

找了很久也没有找到文字滚动的控制方式 ,只能利用了ScrollToCaret()来控制。

ScrollToCaret()只要光标能显示出来,就不再滚动,控制起来有些不够丝滑!同时滑块的位置计算也不是很精准,只是大概这样子。
 

----end----夜已深。不详写了,有兴趣的同学可以下载资源:

C#重写Winform的Textbox单行模式下滚动条。-C#文档类资源-CSDN下载

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值