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 = ;//多行文本框的行数-->估算值
- private const int X = ;//气泡箭头三角形的高
- private const int Round = ;//圆角半径
- private const int M = ;//文本框和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, );
- 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(, );
- }
- //从文本中找到匹配的内容,然后改变前景色或者背景色,返回值是txtWords中匹配的个数。foreColorIndex和backColorIndex用来控制只改其中指定的一个匹配内容的颜色。
- public int SelectSomething(string something, Color[] changeForeColor = null, int foreColorIndex = , Color[] changeBackColor = null, int backColorIndex = )
- {
- int count = ;//匹配个数
- int start = txtWords.Find(something, , RichTextBoxFinds.None);//匹配内容开始索引
- if (start >= )//存在匹配内容
- {
- count++;
- txtWords.SelectionStart = start;
- txtWords.SelectionLength = something.Length;
- if (changeForeColor != null && changeForeColor.Length > )
- {
- if (foreColorIndex <= || (foreColorIndex > && foreColorIndex == count))
- {
- txtWords.SelectionColor = changeForeColor[];//改变前景色
- }
- }
- if (changeBackColor != null && changeBackColor.Length > )
- {
- if (backColorIndex <= || (backColorIndex > && backColorIndex == count))
- {
- txtWords.SelectionBackColor = changeBackColor[];//改变背景色
- }
- }
- //匹配下一个
- while (txtWords.Text.Length > start + something.Length)
- {
- start = txtWords.Find(something, start + something.Length, RichTextBoxFinds.None);
- if (start >= )
- {
- count++;
- txtWords.SelectionStart = start;
- txtWords.SelectionLength = something.Length;
- if (changeForeColor != null && changeForeColor.Length > )
- {
- if (foreColorIndex <= || (foreColorIndex > && foreColorIndex == count))
- {
- txtWords.SelectionColor = changeForeColor[];//改变前景色
- }
- }
- if (changeBackColor != null && changeBackColor.Length > )
- {
- if (backColorIndex <= || (backColorIndex > && backColorIndex == count))
- {
- txtWords.SelectionBackColor = changeBackColor[];//改变背景色
- }
- }
- }
- else
- break;
- }
- }
- //返回匹配个数
- return count;
- }
- //还原富文本框的颜色
- public void ClearSomething()
- {
- txtWords.SelectionStart = ;
- 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 = ;
- char[] chars = words.ToCharArray();
- for (int i = ; 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 > )
- txtWords.Width = this.Width - X - M - M; //文本框的宽度=控件宽度-箭头高-左侧留白-右侧留白
- else
- txtWords.Width = lblWords.Width;
- txtWords.Height = rowsCount * font.Height;
- //调整误差
- if (font.Size == )
- txtWords.Height += rowsCount * ;
- else if (font.Size == )
- txtWords.Height += rowsCount * ;
- else if (font.Size == )
- txtWords.Height += rowsCount * ;
- else if (font.Size == )
- txtWords.Height += rowsCount * ;
- else if (font.Size == )
- txtWords.Height += rowsCount * ;
- else
- txtWords.Height += rowsCount * (font.Height / );
- //整个uc的高度
- this.Height = txtWords.Height + M + M;
- //位置
- if (this.direction == "left")
- {
- txtWords.Location = new Point(X + M, M);
- }
- else
- {
- if (rowsCount > )
- 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 > )
- {
- //背景
- Point[] points = new Point[]
- {
- //左上角
- new Point(X,Round),
- new Point(X+Round,),
- //右上角
- new Point(this.Width-Round,),
- 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, , Round * , Round * );//左上圆角
- graphics.FillEllipse(brush, this.Width - Round * , , Round * , Round * );//右上圆角
- graphics.FillEllipse(brush, this.Width - Round * , this.Height - Round * , Round * , Round * );//右下圆角
- graphics.FillEllipse(brush, X, this.Height - Round * , Round * , Round * );//左下圆角
- //三角形
- Point[] points2 = new Point[]
- {
- new Point(X,),
- new Point( ,),
- new Point(X,)
- };
- graphics.FillPolygon(brush, points2);
- }
- else
- {
- //背景
- Point[] points = new Point[]
- {
- //左上角
- new Point(X,Round),
- new Point(X+Round,),
- //右上角
- new Point(lblMax-Round,),
- 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, , Round * , Round * );//左上圆角
- graphics.FillEllipse(brush, lblMax - Round * , , Round * , Round * );//右上圆角
- graphics.FillEllipse(brush, lblMax - Round * , this.Height - Round * , Round * , Round * );//右下圆角
- graphics.FillEllipse(brush, X, this.Height - Round * , Round * , Round * );//左下圆角
- //三角形
- Point[] points2 = new Point[]
- {
- new Point(X,),
- new Point( ,),
- new Point(X,)
- };
- 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 > )
- {
- //背景
- Point[] points = new Point[]
- {
- //左上角
- new Point(,Round),
- new Point(Round,),
- //右上角
- new Point(this.Width-X-Round,),
- 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(,this.Height-Round)
- };
- graphics.FillPolygon(brush, points);
- //绘制圆角
- graphics.FillEllipse(brush, , , Round * , Round * );//左上圆角
- graphics.FillEllipse(brush, this.Width - X - Round * , , Round * , Round * );//右上圆角
- graphics.FillEllipse(brush, this.Width - X - Round * , this.Height - Round * , Round * , Round * );//右下圆角
- graphics.FillEllipse(brush, , this.Height - Round * , Round * , Round * );//左下圆角
- //三角形
- Point[] points2 = new Point[]
- {
- new Point(this.Width-X,),
- new Point(this.Width,),
- new Point(this.Width-X,)
- };
- graphics.FillPolygon(brush, points2);
- }
- else
- {
- //背景
- Point[] points = new Point[]
- {
- //左上角
- new Point(this.Width-lblMax,Round),
- new Point(this.Width-lblMax+Round,),
- //右上角
- new Point(this.Width-X-Round,),
- 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, , Round * , Round * );//左上圆角
- graphics.FillEllipse(brush, this.Width - X - Round * , , Round * , Round * );//右上圆角
- graphics.FillEllipse(brush, this.Width - X - Round * , this.Height - Round * , Round * , Round * );//右下圆角
- graphics.FillEllipse(brush, this.Width - lblMax, this.Height - Round * , Round * , Round * );//左下圆角
- //三角形
- Point[] points2 = new Point[]
- {
- new Point(this.Width-X,),
- new Point(this.Width,),
- new Point(this.Width-X,)
- };
- 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 == )
- {
- e.Handled = true;
- if (BubbleKeyPress != null)
- BubbleKeyPress();
- }
- }
- #endregion
- }
- }
使用:
- ucBubble uc1 = new ucBubble(, Color.Brown, Color.Red, Color.Black, , "微软雅黑", "Hello World!", "left");
- uc1.Location = new Point(, );
- this.Controls.Add(uc1);
- ucBubble uc2 = new ucBubble(, Color.Brown, Color.Green, Color.Black, , "微软雅黑", "Hello World!", "right");
- uc2.Location = new Point(, );
- this.Controls.Add(uc2);
- ucBubble uc3 = new ucBubble(, Color.Brown, Color.Red, Color.Black, , "微软雅黑", "Hello World!Hello World!Hello World!Hello World!Hello World!", "left");
- uc3.Location = new Point(, );
- this.Controls.Add(uc3);
- ucBubble uc4 = new ucBubble(, Color.Brown, Color.Green, Color.Black, , "微软雅黑", "Hello World!Hello World!Hello World!Hello World!", "right");
- uc4.Location = new Point(, );
- this.Controls.Add(uc4);
效果:
WindowsForm--Bubble User Control的更多相关文章
- Massively parallel supercomputer
A novel massively parallel supercomputer of hundreds of teraOPS-scale includes node architectures ba ...
- Control Flow 如何处理 Error
在Package的执行过程中,如果在Data Flow中出现Error,那么Data Flow component能够将错误行输出,只需要在组件的ErrorOutput中进行简单地配置,参考<D ...
- Tutorial: WPF User Control for AX2012
原作者: https://community.dynamics.com/ax/b/goshoom/archive/2011/10/06/tutorial-wpf-user-control-for-ax ...
- wpf custom control
最近在做WPF,记录一下自定义控件的制作过程,源码请点击:源码. 1.目标 实现一个如图所示的可增减的数字框: 2.先画Template 可以在Generic.xaml中画,也可以用MergedDic ...
- [译]Stairway to Integration Services Level 9 - Control Flow Task Errors
介绍 在本文中,我们会实验 MaximumErrorCount和ForceExecutioResult 故障容差属性,并且还要学习Control Flow task errors, event han ...
- 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 ...
- 企业管理软件开发架构之七 Object Control设计与运用
在做查询时,经常遇到一类需求.请看下面的SQL语句查询 SELECT * FROM Company WHERE CompanyCode='Kingston' AND Suspended='N' AND ...
- 文字处理控件TX Text Control的使用
这几天一直在研究TX Text Control的使用,由于这方面的资料相对比较少,主要靠下载版本的案例代码进行研究,以及官方的一些博客案例进行学习,使用总结了一些心得,特将其总结出来,供大家分享学习. ...
- Sublime text 2/3 中 Package Control 的安装与使用方法
Package Control 插件是一个方便 Sublime text 管理插件的插件,但因为 Sublime Text 3 更新了 Python 的函数,API不同了,导致基于 Python 开发 ...
- Java中的经典算法之冒泡排序(Bubble Sort)
Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...
随机推荐
- Win10/UWP开发—使用Cortana语音指令与App的前台交互
Win10开发中最具有系统特色的功能点绝对少不了集成Cortana语音指令,其实Cortana语音指令在以前的wp8/8.1时就已经存在了,发展到了Win10,Cortana最明显的进步就是开始支持调 ...
- android view : window
既然是view,为什么要说window,实际上着是一个很有用的东西,在展现view和设计界面上很有用,就比如说悬浮窗 但是这时候又要分清楚一个概念,window到底是什么?在activity中说过了我 ...
- rand & random & arc4random
rand(3) / random(3) / arc4random(3) / et al. Written by Mattt Thompson on August 12th, 2013 What pas ...
- 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 ...
- REDIS 事务机制
基本事务操作: 任何数据库都必须要保证一种原子执行操作:最基本的原子执行操作肯定是需要提供: 举一个例子来说明: 当对某个Key 做一个统计: 可能不同的Client做它那部分的统计,一段时间后,服务 ...
- Nginx 开启gzip 压缩
随着nginx的发展,越来越多的网站使用nginx,因此nginx的优化变得越来越重要,今天我们来看看nginx的gzip压缩到底是怎么压缩的呢? gzip(GNU-ZIP)是一种压缩技术. 经过gz ...
- iOS不使用JSONKit做Dic到JsonString的转换
NSDictionary to jsonString [self DataTOjsonString:dic] -(NSString*)DicToJsonString:(id)object { NSSt ...
- linux系统下,查看端口号被哪个应用占用
netstat -tunlp 会把所有端口和所有对应的程序显示出来. 用grep管道可过滤出来需要的信息.比如,17059端口号被占用了. 第一步:netstat -tunlp | grep 1705 ...
- [非原创]Project facet Java version 1.8 is not supported解决记录
原博地址:http://blog.csdn.net/dingchenxixi/article/details/51496998 一看知道是因为jdk版本不一致所导致,如何解决? 方法一: 选中项目 P ...
- service的简单使用
Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy 我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的. ...