Winform中使用用户控件实现带行数和标尺的RichTextBox(附代码下载)
程序员文章站
2022-11-21 15:28:42
场景 RichTextBox控件允许用户输入和编辑文本的同时提供了比普通的TextBox控件更高级的格式特征。 效果 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书、教程推送与免费下载。 实现 新建一 ......
场景
richtextbox控件允许用户输入和编辑文本的同时提供了比普通的textbox控件更高级的格式特征。
效果
注:
博客主页:
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
实现
新建一个用户控件guagerichtextbox。
编辑用户控件,相当于自己定义了一个控件,和其他控件一样在窗体中使用,是一个类。
然后打开其设计页面,放置一个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 } }
右击项目,生成一下,就可以看到窗体的工具箱上面多了一组工具,可以看到我们定义的控件
代码下载
https://download.csdn.net/download/badao_liumang_qizhi/12240495