欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

程序员文章站 2022-05-29 13:26:19
场景 RichTextBox控件允许用户输入和编辑文本的同时提供了比普通的TextBox控件更高级的格式特征。 效果 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书、教程推送与免费下载。 实现 新建一 ......

场景

richtextbox控件允许用户输入和编辑文本的同时提供了比普通的textbox控件更高级的格式特征。

效果

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

 

 

 

注:

博客主页:

关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

新建一个用户控件guagerichtextbox。

编辑用户控件,相当于自己定义了一个控件,和其他控件一样在窗体中使用,是一个类。

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

 

 

然后打开其设计页面,放置一个richtextbox

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

 

 

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

然后进入其代码

using system;
using system.collections.generic;
using system.componentmodel;
using system.drawing;
using system.data;
using system.linq;
using system.text;
using system.windows.forms;

namespace 带行数和标尺的richtextbox
{
    public partial class guagerichtextbox : usercontrol
    {
        public guagerichtextbox()
        {
            initializecomponent();
            richtextbox1.wordwrap = false;
            richtextbox1.top = distance_x;
            richtextbox1.left = distance_y;
            richtextbox1.width = this.width - distance_x - 2;
            richtextbox1.height = this.height - distance_y - 2;
        }

 

        #region 变量及常量
        const int distance_x = 30;//设置richtextbox控件的x位置
        const int distance_y = 30;//设置richtextbox控件的y位置
        const int spacebetween = 3;//设置标尺的间距
        public static float thisleft = 0;//设置控件的左边距
        public static float startbith = 0;//记录横向滚动条的位置
        public static float startbitv = 0;//记录纵向滚动条的位置
        const int scale1 = 3;//设置刻度最短的线长
        const int scale5 = 6;//设置刻度为5时的线长
        const int scale10 = 9;//设置刻度为10是垢线长
        public static float degree = 0;//度数
        public static float codesize = 1;//代码编号的宽度
        #endregion

        #region 属性

        [browsable(true), category("设置标尺控件"), description("设置richtextbox控件的相关属性")] //在“属性”窗口中显示datastyle属性
        public richtextbox nrichtextbox
        {
            get { return richtextbox1; }
        }

        public enum ruler
        {
            graduation = 0,//刻度
            rule = 1,//尺子
        }

        private bool tcodeshow = false;
        [browsable(true), category("设置标尺控件"), description("是否在richtextbox控件的前面添加代码的行号")] //在“属性”窗口中显示datastyle属性
        public bool codeshow
        {
            get { return tcodeshow; }
            set
            {
                tcodeshow = value;
                this.invalidate();
            }
        }

        private ruler trulerstyle = ruler.graduation;
        [browsable(true), category("设置标尺控件"), description("设置标尺样式:\ngraduation为刻度\nrule为尺子")] //在“属性”窗口中显示datastyle属性
        public ruler rulerstyle
        {
            get { return trulerstyle; }
            set
            {
                trulerstyle = value;
                this.invalidate();
            }
        }

        public enum unit 
        {
            cm = 0,//厘米
            pels = 1,//像素
        }

        private unit tunitstyle = unit.cm;
        [browsable(true), category("设置标尺控件"), description("设置标尺的单位:\ncm为厘米\npels为像素")] //在“属性”窗口中显示datastyle属性
        public unit unitstyle
        {
            get { return tunitstyle; }
            set
            {
                tunitstyle = value;
                this.invalidate();
            }
        }

        #endregion

        #region 事件
        private void guagerichtextbox_paint(object sender, painteventargs e)
        {
            e.graphics.drawrectangle(new pen(color.darkgray), 0, 0, this.width - 1, this.height - 1);//绘制外边框
            if (codeshow)//如查在文本框左边添加行号
            {
                //获取行号的宽度
                float tem_code = (float)stringsize((convert.toint32(codesize+(float)(richtextbox1.height / (stringsize(codesize.tostring(), richtextbox1.font, false))))).tostring(),this.font, true);
                richtextbox1.top = distance_x;//设置控件的顶端距离
                richtextbox1.left = distance_y + (int)math.ceiling(tem_code);//设置控件的左端距离
                richtextbox1.width = this.width - distance_x - 2 - (int)math.ceiling(tem_code);//设置控件的宽度
                richtextbox1.height = this.height - distance_y - 2;//设置控件高度
                thisleft = distance_y + tem_code;//设置标尺的左端位置
            }
            else
            {
                richtextbox1.top = distance_x;//设置控件的顶端距离
                richtextbox1.left = distance_y;//设置控件的左端距离
                richtextbox1.width = this.width - distance_x - 2;//设置控件的宽度
                richtextbox1.height = this.height - distance_y - 2;//设置控件高度
                thisleft = distance_y;//设置标尺的左端位置
            }
            //绘制文本框的边框
            e.graphics.drawrectangle(new pen(color.lightsteelblue), richtextbox1.location.x - 1, thisleft - 1, richtextbox1.width + 1, richtextbox1.height + 1);
            e.graphics.fillrectangle(new solidbrush(color.silver), 1, 1, this.width - 2, distance_y - 2);//文本框的上边框
            e.graphics.fillrectangle(new solidbrush(color.silver), 1, 1, distance_x - 2, this.height - 2);//文本框的左边框
            e.graphics.fillrectangle(new solidbrush(color.gray), 3, 3, distance_x - 7, distance_y - 8);//绘制左上角的方块边框
            e.graphics.drawrectangle(new pen(systemcolors.control), 3, 3, distance_x - 8, distance_y - 8);//绘制左上角的方块
            if (rulerstyle == ruler.rule)//标尺
            {
                //绘制上边的标尺背景
                e.graphics.fillrectangle(new solidbrush(color.gray), thisleft - 3, 3, this.width - (thisleft - 2) , distance_y - 9);//绘制左上角的方块边框
                e.graphics.drawline(new pen(systemcolors.control), thisleft - 3, 3, this.width - 2, 3);//绘制方块的上边线
                e.graphics.drawline(new pen(systemcolors.control), thisleft - 3, distance_y - 5, this.width - 2, distance_y - 5);//绘制方块的下边线
                e.graphics.fillrectangle(new solidbrush(color.whitesmoke), thisleft - 2, 9, this.width - (thisleft - 2) - 1, distance_y - 19);//绘制方块的中间块
                //绘制左边的标尺背景
                e.graphics.fillrectangle(new solidbrush(color.gray), 3, distance_y - 3, distance_x - 7, this.height - (distance_y - 3) - 2);//绘制左边的方块
                e.graphics.drawline(new pen(systemcolors.control), 3, distance_y - 3, 3, this.height - 2);//绘制方块的左边线
                e.graphics.drawline(new pen(systemcolors.control), distance_x - 5, distance_y - 3, distance_x - 5, this.height - 2);//绘制方块的右边线
                e.graphics.fillrectangle(new solidbrush(color.whitesmoke), 9, distance_y - 3, distance_x - 19, this.height - (distance_y - 3) - 2);//绘制方块的中间块
            }
            int tem_temheight = 0;
            string tem_value = "";
            int tem_n = 0;
            int divide = 5;
            pen tem_p = new pen(new solidbrush(color.black));
            //横向刻度的设置
            if (unitstyle == unit.cm)//如果刻度的单位是厘米
                degree = e.graphics.dpix / 25.4f;//将像素转换成毫米
            if (unitstyle == unit.pels)//如果刻度的单位是像素
                degree = 10;//设置10像素为一个刻度
            int tem_width = this.width - 3;
            tem_n = (int)startbith;//记录横向滚动条的位置
            if (tem_n != startbith)//如果横向滚动条的位置值为小数
                startbith = (int)startbith;//对横向滚动条的位置进行取整
            for (float i = 0; i < tem_width; )//在文本框的项端绘制标尺
            {
                tem_temheight = scale1;//设置刻度线的最小长度
                float j = (i + (int)startbith) / degree;//获取刻度值
                tem_value = "";
                j = (int)j;//对刻度值进行取整
                if (j % (divide * 2) == 0)//如果刻度值是10进位
                {
                    tem_temheight = scale10;//设置最长的刻度线
                    if (unitstyle == unit.cm)//如果刻度的单位为厘米
                        tem_value = convert.tostring(j / 10);//记录刻度值
                    if (unitstyle == unit.pels)//如果刻度的单位为像素
                        tem_value = convert.tostring((int)j * 10);//记录刻度值
                }
                else if (j % divide == 0)//如果刻度值的进位为5
                {
                    tem_temheight = scale5;//设置刻度线为中等
                }
                tem_p.width = 1;
                if (rulerstyle == ruler.graduation)//如果是以刻度值进行测量
                {
                    //绘制刻度线
                    e.graphics.drawline(tem_p, i + 1 + thisleft, spacebetween, i + 1 + thisleft, spacebetween + tem_temheight);
                    if (tem_value.length > 0)//如果有刻度值
                        //绘制刻度值
                        protractstring(e.graphics, tem_value.trim(), i + 1 + thisleft, spacebetween, i + 1 + thisleft, spacebetween + tem_temheight, 0);
                }
                if (rulerstyle == ruler.rule)//如果是以标尺进行测量
                {
                    if (tem_value.length > 0)//如果有刻度值
                    {
                        e.graphics.drawline(tem_p, i + 1 + thisleft, 4, i + 1 + thisleft, 7);//绘制顶端的刻度线
                        e.graphics.drawline(tem_p, i + 1 + thisleft, distance_y - 9, i + 1 + thisleft, distance_y - 7);//绘制底端的刻度线
                        float tem_space = 3 + (distance_x - 19f - 9f - stringsize(tem_value.trim(),this.font, false)) / 2f;//设置文本的横向位置
                        //绘制文本
                        protractstring(e.graphics, tem_value.trim(), i + 1 + thisleft, (float)math.ceiling(tem_space), i + 1 + thisleft, (float)math.ceiling(tem_space) + tem_temheight, 0);
                    }
                }
                i += degree;//累加刻度的宽度
            }
            //纵向刻度的设置
            if (unitstyle == unit.cm)//如果刻度的单位是厘米
                degree = e.graphics.dpix / 25.4f;//将像素转换成毫米
            if (unitstyle == unit.pels)//如果刻度的单位是像素
                degree = 10;//刻度值设为10像素
            int tem_height = this.height - 3;
            tem_n = (int)startbitv;//记录纵向滚动条的位置
            if (tem_n != startbitv)//如果纵向滚动条的位置为小数
                startbitv = (int)startbitv;//对其进行取整
            for (float i = 0; i < tem_height; )//在文本框的左端绘制标尺
            {
                tem_temheight = scale1;//设置刻度线的最小值
                float j = (i + (int)startbitv) / degree;//获取当前的刻度值
                tem_value = "";
                j = (int)j;//对刻度值进行取整
                if (j % 10 == 0)//如果刻度值是10进位
                {
                    tem_temheight = scale10;//设置刻度线的长度为最长
                    if (unitstyle == unit.cm)//如果刻度的单位是厘米
                        tem_value = convert.tostring(j / 10);//获取厘米的刻度值
                    if (unitstyle == unit.pels)//如果刻度的单位是像素
                        tem_value = convert.tostring((int)j * 10);//获取像素的刻度值
                }
                else if (j % 5 == 0)//如果刻度值是5进位
                {
                    tem_temheight = scale5;//设置刻度线的长度为中等
                }
                tem_p.width = 1;
                if (rulerstyle == ruler.graduation)//如果是以刻度值进行测量
                {
                    //绘制刻度线
                    e.graphics.drawline(tem_p, spacebetween, i + 1 + distance_y, spacebetween + tem_temheight, i + 1 + distance_y);
                    if (tem_value.length > 0)//如果有刻度值
                        //绘制刻度值
                        protractstring(e.graphics, tem_value.trim(), spacebetween, i + 1 + distance_y, spacebetween + tem_temheight, i + 1 + distance_y, 1);
                }
                if (rulerstyle == ruler.rule)//如果是以标尺进行测量
                {
                    if (tem_value.length > 0)//如果有刻度值
                    {
                        e.graphics.drawline(tem_p, 4, i + 1 + distance_y, 7, i + 1 + distance_y);//绘制左端刻度线
                        e.graphics.drawline(tem_p, distance_y - 9, i + 1 + distance_y, distance_y - 7, i + 1 + distance_y);//绘制右端刻度线
                        float tem_space = 3 + (distance_x - 19f - 9f - stringsize(tem_value.trim(),this.font, false)) / 2f;//设置文本的纵向位置
                        //绘制文本
                        protractstring(e.graphics, tem_value.trim(), (float)math.floor(tem_space), i + 1 + distance_y, (float)math.floor(tem_space) + tem_temheight, i + 1 + distance_y, 1);
                    }
                }
                i += degree;//累加刻度值
            }
            if (codeshow)//如果显示行号
            {
                //设置文本的高度
                float tem_fontheight = (float)(richtextbox1.height / (stringsize(codesize.tostring(), richtextbox1.font, false)));
                float tem_tep = richtextbox1.top;//获取文本框的顶端位置
                int tem_mark = 0;
                for (int i = 0; i < (int)tem_fontheight; i++)//绘制行号
                {
                    tem_mark = i + (int)codesize;//设置代码编号的宽度
                    //绘制行号
                    e.graphics.drawstring(tem_mark.tostring(), this.font, new solidbrush(color.red), new pointf(richtextbox1.left - stringsize(tem_mark.tostring(), this.font, true) - 2, tem_tep));
                    tem_tep = tem_tep + stringsize("懂", richtextbox1.font, false);//设置下一个行号的x坐标值
                }
            }

        }

        private void guagerichtextbox_resize(object sender, eventargs e)
        {
            richtextbox1.top = distance_x;//设置控件的顶端位置
            richtextbox1.left = distance_y;//设置控件的左端位置
            richtextbox1.width = this.width - distance_x - 2;//设置控件的宽度
            richtextbox1.height = this.height - distance_y - 2;//设置控件的高度
            this.invalidate();
        }

        private void richtextbox1_hscroll(object sender, eventargs e)
        {
            startbith = (int)(math.abs((float)richtextbox1.getpositionfromcharindex(0).x - 1));//检索控件横向内指定字符索引处的位置
            this.invalidate();
        }

        private void richtextbox1_vscroll(object sender, eventargs e)
        {
            startbitv = (int)(math.abs((float)richtextbox1.getpositionfromcharindex(0).y - 1));//检索控件纵向内指定字符索引处的位置
            if (codeshow)//如果显示行号
                codesize = (int)math.abs((richtextbox1.getpositionfromcharindex(0).y / stringsize("懂", richtextbox1.font, false)));//设置行号的高度
            this.invalidate();
        }
        #endregion

        #region 方法
        /// <summary>
        /// 在指定的位置绘制文本信息
        /// </summary>
        /// <param e="graphics">封装一个绘图的类对象</param>
        /// <param str="string">文本信息</param> 
        /// <param x1="float">左上角x坐标</param> 
        /// <param y1="float">左上角y坐标</param> 
        /// <param x2="float">右下角x坐标</param> 
        /// <param y2="float">右下角y坐标</param> 
        /// <param n="float">标识,判断是在横向标尺上绘制文字还是在纵向标尺上绘制文字</param> 
        public void protractstring(graphics e, string str, float x1, float y1, float x2, float y2, float n)
        {
            float titwidth = stringsize(str,this.font, true);//获取字符串的宽度
            if (n == 0)//在横向标尺上绘制文字
                e.drawstring(str, this.font, new solidbrush(color.black), new pointf(x2 - titwidth / 2, y2 + 1));
            else//在纵向标尺上绘制文字
            {
                stringformat drawformat = new stringformat();//实例化stringformat类
                drawformat.formatflags = stringformatflags.directionvertical;//设置文本为垂直对齐
                //绘制指定的文本
                e.drawstring(str, this.font, new solidbrush(color.black), new pointf(x2 + 1, y2 - titwidth / 2), drawformat);
            }
        }

        /// <summary>
        /// 获取文本的高度或宽度
        /// </summary>
        /// <param str="string">文本信息</param>
        /// <param font="font">字体样式</param> 
        /// <param n="bool">标识,判断返回的是高度还是宽度</param> 
        public float stringsize(string str,font font,bool n)//n==true为width
        {
            graphics titg = this.creategraphics();//创建graphics类对象
            sizef titsize = titg.measurestring(str, font);//将绘制的字符串进行格式化
            float titwidth = titsize.width;//获取字符串的宽度
            float titheight = titsize.height;//获取字符串的高度
            if (n)
                return titwidth;//返回文本信息的宽度
            else
                return titheight;//返回文本信息的高度
        }
        #endregion
    }
}

 

右击项目,生成一下,就可以看到窗体的工具箱上面多了一组工具,可以看到我们定义的控件

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

 

 

Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)

代码下载

https://download.csdn.net/download/badao_liumang_qizhi/12240495