创建一个自定义用户控件,拖入一个label:lblWords,和一个richTextBox:txtWords
代码:
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 WinBubble { public partial class ucBubble : UserControl { #region 属性字段 private Color gdiBackColor;//GDI+绘制的背景色-->如果和txt背景色不一致,在文本框和GDI+背景色之间会形成一个边框效果 private Color txtBackColor;//多行文本框的背景色 private Color foreColor;//多行文本框的前景色 private Font font;//字体 private string words;//文本 private string direction;//气泡箭头方向 private int rowsCount = 0;//多行文本框的行数-->估算值 private const int X = 6;//气泡箭头三角形的高 private const int Round = 8;//圆角半径 private const int M = 5;//文本框和uc边框的距离 public string CurrentText { get { return txtWords.Text.Replace("\n", ""); } }//文本框的内容 public string SelectedText { get { return txtWords.SelectedText; } }//选中的内容 #endregion #region 接口 public ucBubble(int width, Color gdiBackColor, Color txtBackColor, Color foreColor, int fontSize, string fontFamily, string words, string direction) { InitializeComponent(); this.Width = width; this.gdiBackColor = gdiBackColor; this.txtBackColor = txtBackColor; this.foreColor = foreColor; this.font = new Font(new FontFamily(string.IsNullOrEmpty(fontFamily) ? "微软雅黑" : fontFamily), fontSize); this.words = words; this.direction = direction == "right" ? "right" : "left"; //内容文本框 txtWords.BorderStyle = BorderStyle.None; txtWords.ScrollBars = RichTextBoxScrollBars.None; txtWords.ImeMode = ImeMode.OnHalf; txtWords.BackColor = txtBackColor; txtWords.ForeColor = foreColor; txtWords.Text = words; txtWords.Font = font; //lblWords标签的作用是用来判断文本框内容是不是多行的,因为单行内容需要根据宽度进行定位。如果是单行内容,就让文本框的宽度和标签的宽度相等 lblWords.Visible = false; lblWords.Location = new Point(X + M, 0); lblWords.Text = ""; lblWords.Font = font; //事件 this.Paint += new PaintEventHandler(ucBubble_Paint); this.MouseWheel += new MouseEventHandler(ucBubble_MouseWheel); this.MouseClick += new MouseEventHandler(ucBubble_MouseClick); this.DoubleClick += new EventHandler(ucBubble_DoubleClick); txtWords.MouseWheel += new MouseEventHandler(ucBubble_MouseWheel); txtWords.MouseClick += new MouseEventHandler(ucBubble_MouseClick); txtWords.DoubleClick += new EventHandler(ucBubble_DoubleClick); txtWords.KeyPress += new KeyPressEventHandler(txtWords_KeyPress); rowsCount = GetRowsCount(); ControlRichTextBox(); SelectWords(0, 0); } //从文本中找到匹配的内容,然后改变前景色或者背景色,返回值是txtWords中匹配的个数。foreColorIndex和backColorIndex用来控制只改其中指定的一个匹配内容的颜色。 public int SelectSomething(string something, Color[] changeForeColor = null, int foreColorIndex = 0, Color[] changeBackColor = null, int backColorIndex = 0) { int count = 0;//匹配个数 int start = txtWords.Find(something, 0, RichTextBoxFinds.None);//匹配内容开始索引 if (start >= 0)//存在匹配内容 { count++; txtWords.SelectionStart = start; txtWords.SelectionLength = something.Length; if (changeForeColor != null && changeForeColor.Length > 0) { if (foreColorIndex <= 0 || (foreColorIndex > 0 && foreColorIndex == count)) { txtWords.SelectionColor = changeForeColor[0];//改变前景色 } } if (changeBackColor != null && changeBackColor.Length > 0) { if (backColorIndex <= 0 || (backColorIndex > 0 && backColorIndex == count)) { txtWords.SelectionBackColor = changeBackColor[0];//改变背景色 } } //匹配下一个 while (txtWords.Text.Length > start + something.Length) { start = txtWords.Find(something, start + something.Length, RichTextBoxFinds.None); if (start >= 0) { count++; txtWords.SelectionStart = start; txtWords.SelectionLength = something.Length; if (changeForeColor != null && changeForeColor.Length > 0) { if (foreColorIndex <= 0 || (foreColorIndex > 0 && foreColorIndex == count)) { txtWords.SelectionColor = changeForeColor[0];//改变前景色 } } if (changeBackColor != null && changeBackColor.Length > 0) { if (backColorIndex <= 0 || (backColorIndex > 0 && backColorIndex == count)) { txtWords.SelectionBackColor = changeBackColor[0];//改变背景色 } } } else break; } } //返回匹配个数 return count; } //还原富文本框的颜色 public void ClearSomething() { txtWords.SelectionStart = 0; txtWords.SelectionLength = txtWords.Text.Length; txtWords.SelectionColor = foreColor; txtWords.SelectionBackColor = txtBackColor; } //选中内容 public void SelectWords(int start, int length) { txtWords.Select(start, length); } #endregion #region 方法 //获取文本内容占用的行数 private int GetRowsCount() { int count = 1; char[] chars = words.ToCharArray(); for (int i = 0; i < chars.Length; i++) { lblWords.Text = lblWords.Text + chars[i]; if (X + M + lblWords.Width + M > this.Width) { lblWords.Text = ""; i--; count++; } } return count; } //控制文本框的位置和大小 private void ControlRichTextBox() { if (rowsCount > 1) txtWords.Width = this.Width - X - M - M; //文本框的宽度=控件宽度-箭头高-左侧留白-右侧留白 else txtWords.Width = lblWords.Width; txtWords.Height = rowsCount * font.Height; //调整误差 if (font.Size == 9) txtWords.Height += rowsCount * 7; else if (font.Size == 12) txtWords.Height += rowsCount * 7; else if (font.Size == 16) txtWords.Height += rowsCount * 8; else if (font.Size == 18) txtWords.Height += rowsCount * 9; else if (font.Size == 20) txtWords.Height += rowsCount * 10; else txtWords.Height += rowsCount * (font.Height / 4); //整个uc的高度 this.Height = txtWords.Height + M + M; //位置 if (this.direction == "left") { txtWords.Location = new Point(X + M, M); } else { if (rowsCount > 1) txtWords.Location = new Point(M, M); else txtWords.Location = new Point(this.Width - lblWords.Width - X - M, M); } } //绘制箭头和圆角:气泡箭头在左侧 private void DrawBubbleLeft(Graphics graphics, Color c) { SolidBrush brush = new SolidBrush(c);//定义画刷 int lblMax = X + M + lblWords.Width + M; if (rowsCount > 1) { //背景 Point[] points = new Point[] { //左上角 new Point(X,Round), new Point(X+Round,0), //右上角 new Point(this.Width-Round,0), new Point(this.Width,Round), //右下角 new Point(this.Width,this.Height-Round), new Point(this.Width -Round,this.Height), //左下角 new Point(X+Round ,this.Height), new Point(X,this.Height-Round) }; graphics.FillPolygon(brush, points); //绘制圆角 graphics.FillEllipse(brush, X, 0, Round * 2, Round * 2);//左上圆角 graphics.FillEllipse(brush, this.Width - Round * 2, 0, Round * 2, Round * 2);//右上圆角 graphics.FillEllipse(brush, this.Width - Round * 2, this.Height - Round * 2, Round * 2, Round * 2);//右下圆角 graphics.FillEllipse(brush, X, this.Height - Round * 2, Round * 2, Round * 2);//左下圆角 //三角形 Point[] points2 = new Point[] { new Point(X,12), new Point( 0,17), new Point(X,22) }; graphics.FillPolygon(brush, points2); } else { //背景 Point[] points = new Point[] { //左上角 new Point(X,Round), new Point(X+Round,0), //右上角 new Point(lblMax-Round,0), new Point(lblMax,Round), //右下角 new Point(lblMax,this.Height-Round), new Point(lblMax -Round,this.Height), //左下角 new Point(X+Round ,this.Height), new Point(X,this.Height-Round) }; graphics.FillPolygon(brush, points); //绘制圆角 graphics.FillEllipse(brush, X, 0, Round * 2, Round * 2);//左上圆角 graphics.FillEllipse(brush, lblMax - Round * 2, 0, Round * 2, Round * 2);//右上圆角 graphics.FillEllipse(brush, lblMax - Round * 2, this.Height - Round * 2, Round * 2, Round * 2);//右下圆角 graphics.FillEllipse(brush, X, this.Height - Round * 2, Round * 2, Round * 2);//左下圆角 //三角形 Point[] points2 = new Point[] { new Point(X,12), new Point( 0,17), new Point(X,22) }; graphics.FillPolygon(brush, points2); } } //绘制箭头和圆角:气泡箭头在右侧 private void DrawBubbleRight(Graphics graphics, Color c) { SolidBrush brush = new SolidBrush(c);//定义画刷 int lblMax = X + M + lblWords.Width + M; if (rowsCount > 1) { //背景 Point[] points = new Point[] { //左上角 new Point(0,Round), new Point(Round,0), //右上角 new Point(this.Width-X-Round,0), new Point(this.Width-X,Round), //右下角 new Point(this.Width-X,this.Height-Round), new Point(this.Width-X-Round,this.Height), //左下角 new Point(Round ,this.Height), new Point(0,this.Height-Round) }; graphics.FillPolygon(brush, points); //绘制圆角 graphics.FillEllipse(brush, 0, 0, Round * 2, Round * 2);//左上圆角 graphics.FillEllipse(brush, this.Width - X - Round * 2, 0, Round * 2, Round * 2);//右上圆角 graphics.FillEllipse(brush, this.Width - X - Round * 2, this.Height - Round * 2, Round * 2, Round * 2);//右下圆角 graphics.FillEllipse(brush, 0, this.Height - Round * 2, Round * 2, Round * 2);//左下圆角 //三角形 Point[] points2 = new Point[] { new Point(this.Width-X,12), new Point(this.Width,17), new Point(this.Width-X,22) }; graphics.FillPolygon(brush, points2); } else { //背景 Point[] points = new Point[] { //左上角 new Point(this.Width-lblMax,Round), new Point(this.Width-lblMax+Round,0), //右上角 new Point(this.Width-X-Round,0), new Point(this.Width-X,Round), //右下角 new Point(this.Width-X,this.Height-Round), new Point(this.Width-X-Round,this.Height), //左下角 new Point(this.Width-lblMax+Round ,this.Height), new Point(this.Width-lblMax,this.Height-Round) }; graphics.FillPolygon(brush, points); //绘制圆角 graphics.FillEllipse(brush, this.Width - lblMax, 0, Round * 2, Round * 2);//左上圆角 graphics.FillEllipse(brush, this.Width - X - Round * 2, 0, Round * 2, Round * 2);//右上圆角 graphics.FillEllipse(brush, this.Width - X - Round * 2, this.Height - Round * 2, Round * 2, Round * 2);//右下圆角 graphics.FillEllipse(brush, this.Width - lblMax, this.Height - Round * 2, Round * 2, Round * 2);//左下圆角 //三角形 Point[] points2 = new Point[] { new Point(this.Width-X,12), new Point(this.Width,17), new Point(this.Width-X,22) }; graphics.FillPolygon(brush, points2); } } #endregion #region 事件 //绘制气泡事件 public void ucBubble_Paint(object sender, PaintEventArgs e) { Graphics graphics = e.Graphics; if (direction == "left") DrawBubbleLeft(graphics, gdiBackColor); else DrawBubbleRight(graphics, gdiBackColor); } //滚动事件 public event Action BubbleMouseWheel; public void ucBubble_MouseWheel(object sender, MouseEventArgs e) { if (BubbleMouseWheel != null) BubbleMouseWheel(); } //单击事件 public event Action BubbleClick; public void ucBubble_MouseClick(object sender, MouseEventArgs e) { if (BubbleClick != null) BubbleClick(); } //双击事件 public event Action BubbleDoubleClick; public void ucBubble_DoubleClick(object sender, EventArgs e) { if (BubbleDoubleClick != null) BubbleDoubleClick(); } //回车事件 public event Action BubbleKeyPress; public void txtWords_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == 13) { e.Handled = true; if (BubbleKeyPress != null) BubbleKeyPress(); } } #endregion } }
使用:
ucBubble uc1 = new ucBubble(250, Color.Brown, Color.Red, Color.Black, 12, "微软雅黑", "Hello World!", "left"); uc1.Location = new Point(20, 20); this.Controls.Add(uc1); ucBubble uc2 = new ucBubble(250, Color.Brown, Color.Green, Color.Black, 12, "微软雅黑", "Hello World!", "right"); uc2.Location = new Point(350, 40); this.Controls.Add(uc2); ucBubble uc3 = new ucBubble(150, Color.Brown, Color.Red, Color.Black, 12, "微软雅黑", "Hello World!Hello World!Hello World!Hello World!Hello World!", "left"); uc3.Location = new Point(20, 80); this.Controls.Add(uc3); ucBubble uc4 = new ucBubble(250, Color.Brown, Color.Green, Color.Black, 12, "微软雅黑", "Hello World!Hello World!Hello World!Hello World!", "right"); uc4.Location = new Point(350, 280); this.Controls.Add(uc4);
效果: