在网上自绘tabcontrol的基础上增强,大部分代码写了注释。
关闭按钮的绘制思路:对padding属性修改以增加标签空白部分。在空白部分绘制十字,写个鼠标在十字区域点击关闭的事件以在适用控件时处理一些必要事情。
tip小字思路:需要显示TIP时,在标签合适位置绘制半透明背景,同时绘制需要显示的TIP文字。对控件增加个需要绘制标签的容器以储存需要绘制TIP的标签及相应文字。写个公用方法在外部调用以将需要绘制tip的标签名和文字传递给控件。
呼吸灯效果思路:以timer控件控制标签背景色的改变从而实现动画效果。对控件增加个容器以储存需要呼吸灯效果的标签名,绘制时标签名判断是否在容器内从而决定是否对标签背景色进行变化。
资源下载:点击打开链接
using System.Collections.Generic;
using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace MyTabControl
{
public partial class MyTabControlEx:TabControl
{
#region 本地参数
/// <summary>
/// 以下三行数据为呼吸灯相关过程数据
/// </summary>
int key = 1;
float step = 10;
int ima = 0, br, bg, bb;
/// <summary>
/// 呼吸灯传递过程颜色
/// </summary>
private Color _tabbaseColor = Color.FromArgb(166, 222, 255);//标签颜色
/// <summary>
/// 基础颜色
/// </summary>
private Color _baseColor = Color.FromArgb(166, 222, 255);//标签颜色
/// <summary>
/// 背景色
/// </summary>
private Color _backColor = Color.FromArgb(234, 247, 254);//背景色
private Color _borderColor = Color.FromArgb(23, 169, 254);//框线颜色
private Color _flashColor = Color.LightYellow;//呼吸灯效果颜色
private Color _tipBackColor = Color.DarkBlue;//标签tip的背景色
private Color _tipTextColor = Color.White;//标签tip的字体颜色
/// <summary>
/// tab标签圆角直径
/// </summary>
private static readonly int Radius = 8;
private bool _haveCloseButton=false;
private bool _drawTipText = false;
private int _lastSelectIndex=-1;
private int _selectIndex=0;
private Timer flashTime = new Timer();//控制标签页闪烁的时间控件
/// <summary>
/// 具有呼吸灯效果标签的数组容器
/// </summary>
Dictionary<string,bool> tabFlickerDictionary=new Dictionary<string,bool>();
/// <summary>
/// 记录标签Tip文字的容器
/// </summary>
Dictionary<string,string> TipTextDictionary = new Dictionary<string,string>();
#endregion
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
public MyTabControlEx()
: base()
{
flashTime.Interval = 50;//控制呼吸灯效果的时间控件
flashTime.Enabled=false;
flashTime.Tick += new EventHandler(tabFlicker_timer_Tick);
_tabbaseColor = _baseColor;
if (TabPages.Count > 0) _lastSelectIndex = 0;
SetStyles();
}
#endregion
#region 事件
/// <summary>
/// 事件委托
/// </summary>
/// <param name="sender">传递本tabControl的指针</param>
/// <param name="e"></param>
public delegate void tabCloseEventHandle(object sender, MouseEventArgs e);
/// <summary>
/// 选中标签页在关闭前触发事件(tabcontrol的select标签页关闭前触发),与controlremoved事件相似
/// </summary>
[Browsable(true)]
[Description("标签页点击关闭按钮后,关闭前触发的事件")]
[EditorBrowsable(EditorBrowsableState.Always)]
public event tabCloseEventHandle tabClose;
#endregion
#region 属性
/// <summary>
/// 控件基础颜色
/// </summary>
[Category("外观")]
[Description("控件标签基础颜色")]
[DefaultValue(typeof(Color), "166, 222, 255")]
public Color BaseColor
{
get { return _baseColor; }
set
{
_baseColor = value;
base.Invalidate(true);
}
}
/// <summary>
/// 背景色
/// </summary>
[Browsable(true)]
[Category("外观")]
[Description("控件背景颜色")]
[EditorBrowsable(EditorBrowsableState.Always)]
[DefaultValue(typeof(Color), "234, 247, 254")]
public override Color BackColor
{
get { return _backColor; }
set
{
_backColor = value;
base.Invalidate(true);
}
}
/// <summary>
/// 边框线条颜色
/// </summary>
[Category("外观")]
[Description("控件边框颜色")]
[DefaultValue(typeof(Color), "23, 169, 254")]
public Color BorderColor
{
get { return _borderColor; }
set
{
_borderColor = value;
base.Invalidate(true);
}
}
/// <summary>
/// Tab标签呼吸灯效果的颜色。
/// </summary>
[Category("外观")]
[Description("控件标签呼吸灯颜色")]
[DefaultValue(typeof(Color), "0, 95, 152")]
public Color 标签呼吸灯颜色
{
get { return _flashColor; }
set
{
_flashColor = value;
}
}
/// <summary>
/// 标签tip背景颜色
/// </summary>
[Category("外观")]
[Description("标签tip背景颜色")]
[DefaultValue(typeof(Color), "0, 128, 255")]
public Color TipBackColor
{
get { return _tipBackColor; }
set
{
_tipBackColor = value;
}
}
/// <summary>
/// 标签tip字体颜色
/// </summary>
[Category("外观")]
[Description("标签tip字体颜色")]
[DefaultValue(typeof(Color), "255, 255, 255")]
public Color TipTextColor
{
get { return _tipTextColor; }
set
{
_tipTextColor = value;
}
}
/// <summary>
/// 是否绘制关闭按钮
/// </summary>
[Category("外观")]
[Description("是否绘制标签的关闭按钮")]
[DefaultValue(typeof(bool), "false")]
public bool HaveCloseButton
{
get {return _haveCloseButton; }
set
{
_haveCloseButton = value;
if (_haveCloseButton) //绘制关闭按钮后对按钮周围空间量进行调整
{
this.Padding = new Point(9, 3);
}
else { this.Padding = new Point(6, 3); }
}
}
/// <summary>
/// 是否在标签绘制提示
/// </summary>
[Category("外观")]
[Description("是否绘制标签提示小字")]
[DefaultValue(typeof(bool), "false")]
public bool ShowDrawTipText
{
get { return _drawTipText; }
set
{
_drawTipText= value;
this.Padding = new Point(this.Padding.X,4) ;
}
}
#endregion
#region 对控件部分方法重写
/// <summary>
/// 对SelectedIndexChanged重写,在标签改变时记录上次选中的标签;移除当前标签特效
/// </summary>
/// <param name="e"></param>
protected override void OnSelectedIndexChanged(EventArgs e)
{
SelectIndexLog();
//以下判断语句移除当前选择项的呼吸灯效果和标签显示效果
if (TabPages.Count > 0&SelectedTab!=null)
{
if (tabFlickerDictionary.ContainsKey(SelectedTab.Name)) tabFlickerRemove(SelectedTab.Name);
if (TipTextDictionary.ContainsKey(SelectedTab.Name)) TipTextDictionary.Remove(SelectedTab.Name);
}
else if (TabPages.Count <= 0)
{
tabFlickerDictionary.Clear();
TipTextDictionary.Clear();
}
base.OnSelectedIndexChanged(e);
}
/// <summary>
/// 重写鼠标事件,鼠标在关闭区域点击时关闭选项卡
/// </summary>
/// <param name="e"></param>
protected override void OnMouseUp(MouseEventArgs e)
{
if (_haveCloseButton)
{
if (e.Button == MouseButtons.Left)
{
Point cusorPoint = PointToClient(MousePosition);
//计算关闭区域
Rectangle CloseRect =getCloseButtonRect( this.GetTabRect(SelectedIndex));
TabPage checkTab = this.SelectedTab;
//如果鼠标在区域内就关闭选项卡
if (CloseRect.Contains(cusorPoint))
{
if (tabClose != null)//移除选项卡之前执行tabclose事件,此事件在外部调用以在关闭标签时执行用户命令
{ tabClose(this, e); }
SelectedIndex = _lastSelectIndex; //此为设置选项卡为最后一次选择项,
this.TabPages.Remove(checkTab);
SelectIndexLog();
}
}
}
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
base.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
base.Invalidate();
}
/// <summary>
/// 重写绘制事件,执行自定义的标签绘制。关键事件
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
DrawTabContrl(e.Graphics);
}
#endregion
#region 公开的自定义方法,在外部调用实现闪烁标签和标签TIP功能
/// <summary>
/// 将tabpage加入呼吸灯显示容器,使标签具有呼吸灯效果
/// </summary>
/// <param name="tabPageName"></param>
public void tabFlickerAdd(string tabPageName)
{
if (SelectedTab != null)
{
if (SelectedTab.Name == tabPageName) //不对当前标签添加呼吸灯效果
{ return; }
}
if (TabPages.ContainsKey(tabPageName))
{
if (!tabFlickerDictionary.ContainsKey(tabPageName))
{
tabFlickerDictionary.Add(tabPageName, false);
if (!flashTime.Enabled) flashTime.Enabled = true;
}
}
}
/// <summary>
/// 将tabpage移除呼吸灯显示容器
/// </summary>
/// <param name="tabPageName"></param>
public void tabFlickerRemove(string tabPageName)
{
if (tabFlickerDictionary.ContainsKey(tabPageName))
{
tabFlickerDictionary.Remove(tabPageName);
}
if (tabFlickerDictionary.Count <= 0) flashTime.Enabled = false;
}
/// <summary>
/// 将需要显示的Tip文字添加到容器以显示
/// </summary>
/// <param name="tabPageName"></param>
/// <param name="text"></param>
public void TipTextAdd(string tabPageName, string text)
{
if (SelectedTab != null)
{
if (SelectedTab.Name == tabPageName) //不对当前标签添加Tip文字
{ return; }
}
if (TabPages.ContainsKey(tabPageName))
{
if (!TipTextDictionary.ContainsKey(tabPageName))
{
TipTextDictionary.Add(tabPageName, text);
}
else
{
TipTextDictionary[tabPageName] = text;
}
}
}
/// <summary>
/// Tip文字不需要显示后从容器移除
/// </summary>
/// <param name="tabPageName"></param>
public void TipTextRemove(string tabPageName)
{
if (TipTextDictionary.ContainsKey(tabPageName))
{
TipTextDictionary.Remove(tabPageName);
}
}
#endregion
#region 过程方法
/// <summary>
/// 对控件基础功能设置。自行绘制,双重缓存忽略WM_ERASEBKGND消息,调整大小重绘,接受ALPHA透明设置
/// </summary>
private void SetStyles()
{
base.SetStyle(
ControlStyles.UserPaint | // 控件将自行绘制,而不是通过操作系统来绘制
ControlStyles.OptimizedDoubleBuffer | // 该控件首先在缓冲区中绘制,而不是直接绘制到屏幕上,这样可以减少闪烁
ControlStyles.AllPaintingInWmPaint | // 控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁
ControlStyles.ResizeRedraw | // 在调整控件大小时重绘控件
ControlStyles.SupportsTransparentBackColor, // 控件接受 alpha 组件小于 255 的 BackColor 以模拟透明
true); // 设置以上值为 true
base.UpdateStyles();
}
/// <summary>
/// 整个控件重绘方法
/// </summary>
/// <param name="g"></param>
private void DrawTabContrl(Graphics g)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
DrawDrawBackgroundAndHeader(g);
DrawTabPages(g);
DrawBorder(g);
}
/// <summary>
/// 绘制整体背景
/// </summary>
/// <param name="g">tabcontrol的绘图面</param>
private void DrawDrawBackgroundAndHeader(Graphics g)
{
int x = 0;
int y = 0;
int width = 0;
int height = 0;
switch (Alignment)
{
case TabAlignment.Top:
x = 0;
y = 0;
width = ClientRectangle.Width;
height = ClientRectangle.Height - DisplayRectangle.Height;
break;
case TabAlignment.Bottom:
x = 0;
y = DisplayRectangle.Height;
width = ClientRectangle.Width;
height = ClientRectangle.Height - DisplayRectangle.Height;
break;
case TabAlignment.Left:
x = 0;
y = 0;
width = ClientRectangle.Width - DisplayRectangle.Width;
height = ClientRectangle.Height;
break;
case TabAlignment.Right:
x = DisplayRectangle.Width;
y = 0;
width = ClientRectangle.Width - DisplayRectangle.Width;
height = ClientRectangle.Height;
break;
}
//标签所在的矩形
Rectangle headerRect = new Rectangle(x, y, width, height);
Color backColor = Enabled ? _backColor : SystemColors.Control;
using (SolidBrush brush = new SolidBrush(backColor))
{
g.FillRectan