WindowsForm--Bubble User Control

创建一个自定义用户控件,拖入一个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);

效果:

 

posted on 2016-11-03 09:54  凡一二三  阅读(463)  评论(0编辑  收藏  举报