创建一个自定义用户控件,拖入一个label:lblWords,和一个richTextBox:txtWords

代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Data;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9.  
  10. namespace WinBubble
  11. {
  12. public partial class ucBubble : UserControl
  13. {
  14. #region 属性字段
  15. private Color gdiBackColor;//GDI+绘制的背景色-->如果和txt背景色不一致,在文本框和GDI+背景色之间会形成一个边框效果
  16. private Color txtBackColor;//多行文本框的背景色
  17. private Color foreColor;//多行文本框的前景色
  18. private Font font;//字体
  19. private string words;//文本
  20. private string direction;//气泡箭头方向
  21. private int rowsCount = ;//多行文本框的行数-->估算值
  22.  
  23. private const int X = ;//气泡箭头三角形的高
  24. private const int Round = ;//圆角半径
  25. private const int M = ;//文本框和uc边框的距离
  26.  
  27. public string CurrentText { get { return txtWords.Text.Replace("\n", ""); } }//文本框的内容
  28. public string SelectedText { get { return txtWords.SelectedText; } }//选中的内容
  29. #endregion
  30.  
  31. #region 接口
  32. public ucBubble(int width, Color gdiBackColor, Color txtBackColor, Color foreColor, int fontSize, string fontFamily, string words, string direction)
  33. {
  34. InitializeComponent();
  35.  
  36. this.Width = width;
  37. this.gdiBackColor = gdiBackColor;
  38. this.txtBackColor = txtBackColor;
  39. this.foreColor = foreColor;
  40. this.font = new Font(new FontFamily(string.IsNullOrEmpty(fontFamily) ? "微软雅黑" : fontFamily), fontSize);
  41. this.words = words;
  42. this.direction = direction == "right" ? "right" : "left";
  43.  
  44. //内容文本框
  45. txtWords.BorderStyle = BorderStyle.None;
  46. txtWords.ScrollBars = RichTextBoxScrollBars.None;
  47. txtWords.ImeMode = ImeMode.OnHalf;
  48. txtWords.BackColor = txtBackColor;
  49. txtWords.ForeColor = foreColor;
  50. txtWords.Text = words;
  51. txtWords.Font = font;
  52.  
  53. //lblWords标签的作用是用来判断文本框内容是不是多行的,因为单行内容需要根据宽度进行定位。如果是单行内容,就让文本框的宽度和标签的宽度相等
  54. lblWords.Visible = false;
  55. lblWords.Location = new Point(X + M, );
  56. lblWords.Text = "";
  57. lblWords.Font = font;
  58.  
  59. //事件
  60. this.Paint += new PaintEventHandler(ucBubble_Paint);
  61. this.MouseWheel += new MouseEventHandler(ucBubble_MouseWheel);
  62. this.MouseClick += new MouseEventHandler(ucBubble_MouseClick);
  63. this.DoubleClick += new EventHandler(ucBubble_DoubleClick);
  64.  
  65. txtWords.MouseWheel += new MouseEventHandler(ucBubble_MouseWheel);
  66. txtWords.MouseClick += new MouseEventHandler(ucBubble_MouseClick);
  67. txtWords.DoubleClick += new EventHandler(ucBubble_DoubleClick);
  68. txtWords.KeyPress += new KeyPressEventHandler(txtWords_KeyPress);
  69.  
  70. rowsCount = GetRowsCount();
  71. ControlRichTextBox();
  72. SelectWords(, );
  73. }
  74.  
  75. //从文本中找到匹配的内容,然后改变前景色或者背景色,返回值是txtWords中匹配的个数。foreColorIndex和backColorIndex用来控制只改其中指定的一个匹配内容的颜色。
  76. public int SelectSomething(string something, Color[] changeForeColor = null, int foreColorIndex = , Color[] changeBackColor = null, int backColorIndex = )
  77. {
  78. int count = ;//匹配个数
  79. int start = txtWords.Find(something, , RichTextBoxFinds.None);//匹配内容开始索引
  80.  
  81. if (start >= )//存在匹配内容
  82. {
  83. count++;
  84. txtWords.SelectionStart = start;
  85. txtWords.SelectionLength = something.Length;
  86. if (changeForeColor != null && changeForeColor.Length > )
  87. {
  88. if (foreColorIndex <= || (foreColorIndex > && foreColorIndex == count))
  89. {
  90. txtWords.SelectionColor = changeForeColor[];//改变前景色
  91. }
  92. }
  93. if (changeBackColor != null && changeBackColor.Length > )
  94. {
  95. if (backColorIndex <= || (backColorIndex > && backColorIndex == count))
  96. {
  97. txtWords.SelectionBackColor = changeBackColor[];//改变背景色
  98. }
  99. }
  100.  
  101. //匹配下一个
  102. while (txtWords.Text.Length > start + something.Length)
  103. {
  104. start = txtWords.Find(something, start + something.Length, RichTextBoxFinds.None);
  105. if (start >= )
  106. {
  107. count++;
  108. txtWords.SelectionStart = start;
  109. txtWords.SelectionLength = something.Length;
  110.  
  111. if (changeForeColor != null && changeForeColor.Length > )
  112. {
  113. if (foreColorIndex <= || (foreColorIndex > && foreColorIndex == count))
  114. {
  115. txtWords.SelectionColor = changeForeColor[];//改变前景色
  116. }
  117. }
  118. if (changeBackColor != null && changeBackColor.Length > )
  119. {
  120. if (backColorIndex <= || (backColorIndex > && backColorIndex == count))
  121. {
  122. txtWords.SelectionBackColor = changeBackColor[];//改变背景色
  123. }
  124. }
  125. }
  126. else
  127. break;
  128. }
  129. }
  130.  
  131. //返回匹配个数
  132. return count;
  133. }
  134.  
  135. //还原富文本框的颜色
  136. public void ClearSomething()
  137. {
  138. txtWords.SelectionStart = ;
  139. txtWords.SelectionLength = txtWords.Text.Length;
  140. txtWords.SelectionColor = foreColor;
  141. txtWords.SelectionBackColor = txtBackColor;
  142. }
  143.  
  144. //选中内容
  145. public void SelectWords(int start, int length)
  146. {
  147. txtWords.Select(start, length);
  148. }
  149. #endregion
  150.  
  151. #region 方法
  152. //获取文本内容占用的行数
  153. private int GetRowsCount()
  154. {
  155. int count = ;
  156. char[] chars = words.ToCharArray();
  157. for (int i = ; i < chars.Length; i++)
  158. {
  159. lblWords.Text = lblWords.Text + chars[i];
  160. if (X + M + lblWords.Width + M > this.Width)
  161. {
  162. lblWords.Text = "";
  163. i--;
  164. count++;
  165. }
  166. }
  167. return count;
  168. }
  169.  
  170. //控制文本框的位置和大小
  171. private void ControlRichTextBox()
  172. {
  173. if (rowsCount > )
  174. txtWords.Width = this.Width - X - M - M; //文本框的宽度=控件宽度-箭头高-左侧留白-右侧留白
  175. else
  176. txtWords.Width = lblWords.Width;
  177.  
  178. txtWords.Height = rowsCount * font.Height;
  179. //调整误差
  180. if (font.Size == )
  181. txtWords.Height += rowsCount * ;
  182. else if (font.Size == )
  183. txtWords.Height += rowsCount * ;
  184. else if (font.Size == )
  185. txtWords.Height += rowsCount * ;
  186. else if (font.Size == )
  187. txtWords.Height += rowsCount * ;
  188. else if (font.Size == )
  189. txtWords.Height += rowsCount * ;
  190. else
  191. txtWords.Height += rowsCount * (font.Height / );
  192.  
  193. //整个uc的高度
  194. this.Height = txtWords.Height + M + M;
  195.  
  196. //位置
  197. if (this.direction == "left")
  198. {
  199. txtWords.Location = new Point(X + M, M);
  200. }
  201. else
  202. {
  203. if (rowsCount > )
  204. txtWords.Location = new Point(M, M);
  205. else
  206. txtWords.Location = new Point(this.Width - lblWords.Width - X - M, M);
  207. }
  208. }
  209.  
  210. //绘制箭头和圆角:气泡箭头在左侧
  211. private void DrawBubbleLeft(Graphics graphics, Color c)
  212. {
  213. SolidBrush brush = new SolidBrush(c);//定义画刷
  214. int lblMax = X + M + lblWords.Width + M;
  215.  
  216. if (rowsCount > )
  217. {
  218. //背景
  219. Point[] points = new Point[]
  220. {
  221. //左上角
  222. new Point(X,Round),
  223. new Point(X+Round,),
  224. //右上角
  225. new Point(this.Width-Round,),
  226. new Point(this.Width,Round),
  227. //右下角
  228. new Point(this.Width,this.Height-Round),
  229. new Point(this.Width -Round,this.Height),
  230. //左下角
  231. new Point(X+Round ,this.Height),
  232. new Point(X,this.Height-Round)
  233. };
  234. graphics.FillPolygon(brush, points);
  235.  
  236. //绘制圆角
  237. graphics.FillEllipse(brush, X, , Round * , Round * );//左上圆角
  238. graphics.FillEllipse(brush, this.Width - Round * , , Round * , Round * );//右上圆角
  239. graphics.FillEllipse(brush, this.Width - Round * , this.Height - Round * , Round * , Round * );//右下圆角
  240. graphics.FillEllipse(brush, X, this.Height - Round * , Round * , Round * );//左下圆角
  241.  
  242. //三角形
  243. Point[] points2 = new Point[]
  244. {
  245. new Point(X,),
  246. new Point( ,),
  247. new Point(X,)
  248. };
  249. graphics.FillPolygon(brush, points2);
  250. }
  251. else
  252. {
  253. //背景
  254. Point[] points = new Point[]
  255. {
  256. //左上角
  257. new Point(X,Round),
  258. new Point(X+Round,),
  259. //右上角
  260. new Point(lblMax-Round,),
  261. new Point(lblMax,Round),
  262. //右下角
  263. new Point(lblMax,this.Height-Round),
  264. new Point(lblMax -Round,this.Height),
  265. //左下角
  266. new Point(X+Round ,this.Height),
  267. new Point(X,this.Height-Round)
  268. };
  269. graphics.FillPolygon(brush, points);
  270.  
  271. //绘制圆角
  272. graphics.FillEllipse(brush, X, , Round * , Round * );//左上圆角
  273. graphics.FillEllipse(brush, lblMax - Round * , , Round * , Round * );//右上圆角
  274. graphics.FillEllipse(brush, lblMax - Round * , this.Height - Round * , Round * , Round * );//右下圆角
  275. graphics.FillEllipse(brush, X, this.Height - Round * , Round * , Round * );//左下圆角
  276.  
  277. //三角形
  278. Point[] points2 = new Point[]
  279. {
  280. new Point(X,),
  281. new Point( ,),
  282. new Point(X,)
  283. };
  284. graphics.FillPolygon(brush, points2);
  285. }
  286. }
  287.  
  288. //绘制箭头和圆角:气泡箭头在右侧
  289. private void DrawBubbleRight(Graphics graphics, Color c)
  290. {
  291. SolidBrush brush = new SolidBrush(c);//定义画刷
  292. int lblMax = X + M + lblWords.Width + M;
  293.  
  294. if (rowsCount > )
  295. {
  296. //背景
  297. Point[] points = new Point[]
  298. {
  299. //左上角
  300. new Point(,Round),
  301. new Point(Round,),
  302. //右上角
  303. new Point(this.Width-X-Round,),
  304. new Point(this.Width-X,Round),
  305. //右下角
  306. new Point(this.Width-X,this.Height-Round),
  307. new Point(this.Width-X-Round,this.Height),
  308. //左下角
  309. new Point(Round ,this.Height),
  310. new Point(,this.Height-Round)
  311. };
  312. graphics.FillPolygon(brush, points);
  313.  
  314. //绘制圆角
  315. graphics.FillEllipse(brush, , , Round * , Round * );//左上圆角
  316. graphics.FillEllipse(brush, this.Width - X - Round * , , Round * , Round * );//右上圆角
  317. graphics.FillEllipse(brush, this.Width - X - Round * , this.Height - Round * , Round * , Round * );//右下圆角
  318. graphics.FillEllipse(brush, , this.Height - Round * , Round * , Round * );//左下圆角
  319.  
  320. //三角形
  321. Point[] points2 = new Point[]
  322. {
  323. new Point(this.Width-X,),
  324. new Point(this.Width,),
  325. new Point(this.Width-X,)
  326. };
  327. graphics.FillPolygon(brush, points2);
  328. }
  329. else
  330. {
  331. //背景
  332. Point[] points = new Point[]
  333. {
  334. //左上角
  335. new Point(this.Width-lblMax,Round),
  336. new Point(this.Width-lblMax+Round,),
  337. //右上角
  338. new Point(this.Width-X-Round,),
  339. new Point(this.Width-X,Round),
  340. //右下角
  341. new Point(this.Width-X,this.Height-Round),
  342. new Point(this.Width-X-Round,this.Height),
  343. //左下角
  344. new Point(this.Width-lblMax+Round ,this.Height),
  345. new Point(this.Width-lblMax,this.Height-Round)
  346. };
  347. graphics.FillPolygon(brush, points);
  348.  
  349. //绘制圆角
  350. graphics.FillEllipse(brush, this.Width - lblMax, , Round * , Round * );//左上圆角
  351. graphics.FillEllipse(brush, this.Width - X - Round * , , Round * , Round * );//右上圆角
  352. graphics.FillEllipse(brush, this.Width - X - Round * , this.Height - Round * , Round * , Round * );//右下圆角
  353. graphics.FillEllipse(brush, this.Width - lblMax, this.Height - Round * , Round * , Round * );//左下圆角
  354.  
  355. //三角形
  356. Point[] points2 = new Point[]
  357. {
  358. new Point(this.Width-X,),
  359. new Point(this.Width,),
  360. new Point(this.Width-X,)
  361. };
  362. graphics.FillPolygon(brush, points2);
  363. }
  364. }
  365. #endregion
  366.  
  367. #region 事件
  368. //绘制气泡事件
  369. public void ucBubble_Paint(object sender, PaintEventArgs e)
  370. {
  371. Graphics graphics = e.Graphics;
  372. if (direction == "left")
  373. DrawBubbleLeft(graphics, gdiBackColor);
  374. else
  375. DrawBubbleRight(graphics, gdiBackColor);
  376. }
  377.  
  378. //滚动事件
  379. public event Action BubbleMouseWheel;
  380. public void ucBubble_MouseWheel(object sender, MouseEventArgs e)
  381. {
  382. if (BubbleMouseWheel != null)
  383. BubbleMouseWheel();
  384. }
  385.  
  386. //单击事件
  387. public event Action BubbleClick;
  388. public void ucBubble_MouseClick(object sender, MouseEventArgs e)
  389. {
  390. if (BubbleClick != null)
  391. BubbleClick();
  392. }
  393.  
  394. //双击事件
  395. public event Action BubbleDoubleClick;
  396. public void ucBubble_DoubleClick(object sender, EventArgs e)
  397. {
  398. if (BubbleDoubleClick != null)
  399. BubbleDoubleClick();
  400. }
  401.  
  402. //回车事件
  403. public event Action BubbleKeyPress;
  404. public void txtWords_KeyPress(object sender, KeyPressEventArgs e)
  405. {
  406. if (e.KeyChar == )
  407. {
  408. e.Handled = true;
  409.  
  410. if (BubbleKeyPress != null)
  411. BubbleKeyPress();
  412. }
  413. }
  414. #endregion
  415. }
  416. }

使用:

  1. ucBubble uc1 = new ucBubble(, Color.Brown, Color.Red, Color.Black, , "微软雅黑", "Hello World!", "left");
  2. uc1.Location = new Point(, );
  3. this.Controls.Add(uc1);
  4.  
  5. ucBubble uc2 = new ucBubble(, Color.Brown, Color.Green, Color.Black, , "微软雅黑", "Hello World!", "right");
  6. uc2.Location = new Point(, );
  7. this.Controls.Add(uc2);
  8.  
  9. ucBubble uc3 = new ucBubble(, Color.Brown, Color.Red, Color.Black, , "微软雅黑", "Hello World!Hello World!Hello World!Hello World!Hello World!", "left");
  10. uc3.Location = new Point(, );
  11. this.Controls.Add(uc3);
  12.  
  13. ucBubble uc4 = new ucBubble(, Color.Brown, Color.Green, Color.Black, , "微软雅黑", "Hello World!Hello World!Hello World!Hello World!", "right");
  14. uc4.Location = new Point(, );
  15. this.Controls.Add(uc4);

效果:

WindowsForm--Bubble User Control的更多相关文章

  1. Massively parallel supercomputer

    A novel massively parallel supercomputer of hundreds of teraOPS-scale includes node architectures ba ...

  2. Control Flow 如何处理 Error

    在Package的执行过程中,如果在Data Flow中出现Error,那么Data Flow component能够将错误行输出,只需要在组件的ErrorOutput中进行简单地配置,参考<D ...

  3. Tutorial: WPF User Control for AX2012

    原作者: https://community.dynamics.com/ax/b/goshoom/archive/2011/10/06/tutorial-wpf-user-control-for-ax ...

  4. wpf custom control

    最近在做WPF,记录一下自定义控件的制作过程,源码请点击:源码. 1.目标 实现一个如图所示的可增减的数字框: 2.先画Template 可以在Generic.xaml中画,也可以用MergedDic ...

  5. [译]Stairway to Integration Services Level 9 - Control Flow Task Errors

    介绍 在本文中,我们会实验 MaximumErrorCount和ForceExecutioResult 故障容差属性,并且还要学习Control Flow task errors, event han ...

  6. Writing a Reusable Custom Control in WPF

    In my previous post, I have already defined how you can inherit from an existing control and define ...

  7. 企业管理软件开发架构之七 Object Control设计与运用

    在做查询时,经常遇到一类需求.请看下面的SQL语句查询 SELECT * FROM Company WHERE CompanyCode='Kingston' AND Suspended='N' AND ...

  8. 文字处理控件TX Text Control的使用

    这几天一直在研究TX Text Control的使用,由于这方面的资料相对比较少,主要靠下载版本的案例代码进行研究,以及官方的一些博客案例进行学习,使用总结了一些心得,特将其总结出来,供大家分享学习. ...

  9. Sublime text 2/3 中 Package Control 的安装与使用方法

    Package Control 插件是一个方便 Sublime text 管理插件的插件,但因为 Sublime Text 3 更新了 Python 的函数,API不同了,导致基于 Python 开发 ...

  10. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

随机推荐

  1. Win10/UWP开发—使用Cortana语音指令与App的前台交互

    Win10开发中最具有系统特色的功能点绝对少不了集成Cortana语音指令,其实Cortana语音指令在以前的wp8/8.1时就已经存在了,发展到了Win10,Cortana最明显的进步就是开始支持调 ...

  2. android view : window

    既然是view,为什么要说window,实际上着是一个很有用的东西,在展现view和设计界面上很有用,就比如说悬浮窗 但是这时候又要分清楚一个概念,window到底是什么?在activity中说过了我 ...

  3. rand & random & arc4random

    rand(3) / random(3) / arc4random(3) / et al. Written by Mattt Thompson on August 12th, 2013 What pas ...

  4. Device eth0 does not seem to be present, delaying initialization(解决克隆CentOS6.3虚拟机后网卡设备无法启动问题)

    1.删除 /etc/udev/rules.d/70-persistent-net.rules 后重启机器 2.重新启动之后,把/etc/udev/rules.d/70-persistent-net.r ...

  5. REDIS 事务机制

    基本事务操作: 任何数据库都必须要保证一种原子执行操作:最基本的原子执行操作肯定是需要提供: 举一个例子来说明: 当对某个Key 做一个统计: 可能不同的Client做它那部分的统计,一段时间后,服务 ...

  6. Nginx 开启gzip 压缩

    随着nginx的发展,越来越多的网站使用nginx,因此nginx的优化变得越来越重要,今天我们来看看nginx的gzip压缩到底是怎么压缩的呢? gzip(GNU-ZIP)是一种压缩技术. 经过gz ...

  7. iOS不使用JSONKit做Dic到JsonString的转换

    NSDictionary to jsonString [self DataTOjsonString:dic] -(NSString*)DicToJsonString:(id)object { NSSt ...

  8. linux系统下,查看端口号被哪个应用占用

    netstat -tunlp 会把所有端口和所有对应的程序显示出来. 用grep管道可过滤出来需要的信息.比如,17059端口号被占用了. 第一步:netstat -tunlp | grep 1705 ...

  9. [非原创]Project facet Java version 1.8 is not supported解决记录

    原博地址:http://blog.csdn.net/dingchenxixi/article/details/51496998 一看知道是因为jdk版本不一致所导致,如何解决? 方法一: 选中项目 P ...

  10. service的简单使用

    Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy 我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的. ...