c#重写TabControl控件实现关闭按钮的方法
发布时间:2022-06-15 01:07:58
1.c#里面的TabControl控件没有关闭按钮,而且很难看。
2.有一些已经做好的第三方控件,但是收费。
3.由于我的故障树推理诊断项目在绘图的时候允许同时打开多个文档进行操作,就要实现类似于浏览器的多标签功能,而且要可以关闭。
4.所以自己写一个类继承TabControl类,然后重写一些里面的方法即可实现。
5.特色:有关闭按钮,标签有背景颜色,选中的标签和没选中的颜色不一样,实现鼠标中键和右键的功能
先看我的项目中的完整代码,有很多代码是我的项目需要,可根据你的项目需求删减,核心的代码后面详细解释:
/// <summary>
/// 重写的TabControl控件 带关闭按钮
/// </summary>
public class MyTabControl : TabControl
{
private int iconWidth = 16;
private int iconHeight = 16;
private Image icon = null;
private Brush biaocolor = Brushes.Silver; //选项卡的背景色
private Form_paint father;//父窗口,即绘图界面,为的是当选项卡全关后调用父窗口的dispose事件关闭父窗口
private AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl axDrawingControl1;
public MyTabControl(AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl axDrawingControl)
: base()
{
this.axDrawingControl1 = axDrawingControl;
this.ItemSize = new Size(50, 25); //设置选项卡标签的大小,可改变高不可改变宽
//this.Appearance = TabAppearance.Buttons; //选项卡的显示模式
this.DrawMode = TabDrawMode.OwnerDrawFixed;
icon = Properties.Resources.close.ToBitmap();
iconWidth = icon.Width; iconHeight = icon.Height;
}
/// <summary>
/// 设置父窗口
/// </summary>
/// <param name="fp">画图窗口</param>
public void setFather(Form_paint fp)
{
this.father = fp;
}
/// <summary>
/// 重写的绘制事件
/// </summary>
/// <param name="e"></param>
protected override void OnDrawItem(DrawItemEventArgs e)//重写绘制事件。
{
Graphics g = e.Graphics;
Rectangle r = GetTabRect(e.Index);
if (e.Index == this.SelectedIndex) //当前选中的Tab页,设置不同的样式以示选中
{
Brush selected_color = Brushes.Gold; //选中的项的背景色
g.FillRectangle(selected_color, r); //改变选项卡标签的背景色
string title = this.TabPages[e.Index].Text + " ";
g.DrawString(title, this.Font, new SolidBrush(Color.Black), new PointF(r.X + 3, r.Y + 6));//PointF选项卡标题的位置
r.Offset(r.Width - iconWidth - 3, 2);
g.DrawImage(icon, new Point(r.X - 2, r.Y + 2));//选项卡上的图标的位置 fntTab = new System.Drawing.Font(e.Font, FontStyle.Bold);
}
else//非选中的
{
g.FillRectangle(biaocolor, r); //改变选项卡标签的背景色
string title = this.TabPages[e.Index].Text + " ";
g.DrawString(title, this.Font, new SolidBrush(Color.Black), new PointF(r.X + 3, r.Y + 6));//PointF选项卡标题的位置
r.Offset(r.Width - iconWidth - 3, 2);
g.DrawImage(icon, new Point(r.X - 2, r.Y + 2));//选项卡上的图标的位置
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
#region 左键判断是否在关闭区域
if (e.Button == MouseButtons.Left)
{
Point p = e.Location;
Rectangle r = GetTabRect(this.SelectedIndex);
r.Offset(r.Width - iconWidth - 3, 2);
r.Width = iconWidth;
r.Height = iconHeight;
if (r.Contains(p)) //点击特定区域时才发生
{
string temp = this.SelectedTab.Text;
if (temp[temp.Length - 5] == '*')//有变化才保存
{
//确认是否保存VSD文档到ft_doc_Path
DialogResult response = MessageBox.Show("是否保存故障树" + this.SelectedTab.Name + "到图形文件", "请确认", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (response == System.Windows.Forms.DialogResult.Yes)//确认保存
{
axDrawingControl1.Document.SaveAs(GlobalVariables.ft_doc_Path + axDrawingControl1.Document.Title + ".vsd");//保存当前文档到文件夹
string datetime = DateTime.Now.ToString();//获取当前时间
helpTool.saveVsdDB(axDrawingControl1.Document.Title, datetime);//保存vsd文档到数据库
helpTool.setDatetimeToXml(axDrawingControl1.Document.Title, datetime);//如果信息已存在则将xml中的日期更新,如果不存在直接插入
this.SelectedTab.Text = temp.Substring(0, temp.Length - 5) + " ";//保存后取消星号标志,还原为没变化的时候的样式
}
else if (response == System.Windows.Forms.DialogResult.Cancel)//点击取消或者关闭
{
return;//直接退出,撤销这次关闭程序的事件。
}
}
if (this.TabCount == 1)//是最后一个选项卡,直接关闭父界面,即画图界面
{
father.DisposeForTabControl(true);
}
else//不是最后一个
{
this.TabPages.Remove(this.SelectedTab);
}
}
}
#endregion
#region 右键 选中
else if (e.Button == MouseButtons.Right) // 右键选中
{
for (int i = 0; i < this.TabPages.Count; i++)
{
TabPage tp = this.TabPages[i];
if (this.GetTabRect(i).Contains(new Point(e.X, e.Y)))
{
this.SelectedTab = tp;
break;
}
}
}
#endregion
#region 中键 选中 关闭
else if (e.Button == MouseButtons.Middle)//鼠标中键关闭
{
for (int i = 0; i < this.TabPages.Count; i++)
{
TabPage tp = this.TabPages[i];
if (this.GetTabRect(i).Contains(new Point(e.X, e.Y)))//找到后,关闭
{
this.SelectedTab = tp;
string temp = tp.Text;
if (temp[temp.Length - 5] == '*')//有变化才保存
{
//确认是否保存VSD文档到ft_doc_Path
DialogResult response = MessageBox.Show("是否保存故障树" + this.SelectedTab.Name + "到图形文件", "请确认", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (response == System.Windows.Forms.DialogResult.Yes)//确认保存
{
axDrawingControl1.Document.SaveAs(GlobalVariables.ft_doc_Path + axDrawingControl1.Document.Title + ".vsd");//保存当前文档到文件夹
string datetime = DateTime.Now.ToString();//获取当前时间
helpTool.saveVsdDB(axDrawingControl1.Document.Title, datetime);//保存vsd文档到数据库
helpTool.setDatetimeToXml(axDrawingControl1.Document.Title, datetime);//如果信息已存在则将xml中的日期更新,如果不存在直接插入
this.SelectedTab.Text = temp.Substring(0, temp.Length - 5) + " ";//保存后取消星号标志,还原为没变化的时候的样式
}
else if (response == System.Windows.Forms.DialogResult.Cancel)//点击取消或者关闭
{
return;//直接退出,撤销这次关闭程序的事件。
}
}
if (this.TabCount == 1)//是最后一个选项卡,直接关闭父界面,即画图界面
{
father.DisposeForTabControl(true);
}
else//不是最后一个
{
this.TabPages.Remove(this.SelectedTab);
}
break;
}
}
}
#endregion
}
}
实现关闭按钮的关键代码是重写OnDrawItem(DrawItemEventArgs e)方法:
protected override void OnDrawItem(DrawItemEventArgs e)//重写绘制事件。
{
Graphics g = e.Graphics;
Rectangle r = GetTabRect(e.Index);
if (e.Index == this.SelectedIndex) //当前选中的Tab页,设置不同的样式以示选中
{
Brush selected_color = Brushes.Gold; //选中的项的背景色
g.FillRectangle(selected_color, r); //改变选项卡标签的背景色
string title = this.TabPages[e.Index].Text + " ";
g.DrawString(title, this.Font, new SolidBrush(Color.Black), new PointF(r.X + 3, r.Y + 6));//PointF选项卡标题的位置
r.Offset(r.Width - iconWidth - 3, 2);
g.DrawImage(icon, new Point(r.X - 2, r.Y + 2));//选项卡上的图标的位置 fntTab = new System.Drawing.Font(e.Font, FontStyle.Bold);
}
else//非选中的
{
g.FillRectangle(biaocolor, r); //改变选项卡标签的背景色
string title = this.TabPages[e.Index].Text + " ";
g.DrawString(title, this.Font, new SolidBrush(Color.Black), new PointF(r.X + 3, r.Y + 6));//PointF选项卡标题的位置
r.Offset(r.Width - iconWidth - 3, 2);
g.DrawImage(icon, new Point(r.X - 2, r.Y + 2));//选项卡上的图标的位置
}
}
其中的if-else是用来判断当前选项卡是否是选中的,使选中的颜色和未选中的不一样,项目中不需要的可以去除。
具体实现关闭功能的原理是重写protected override void OnMouseClick(MouseEventArgs e)方法,左键单击会触发对应事件,判断单击的区域位置是否在关闭按钮的区域,实现关闭功能。另外有对中键和右键的处理,根据你的项目,修改对应按钮事件下的代码即可。
protected override void OnMouseClick(MouseEventArgs e)
{
#region 左键判断是否在关闭区域
if (e.Button == MouseButtons.Left)
{
Point p = e.Location;
Rectangle r = GetTabRect(this.SelectedIndex);
r.Offset(r.Width - iconWidth - 3, 2);
r.Width = iconWidth;
r.Height = iconHeight;
if (r.Contains(p)) //点击特定区域时才发生
{
string temp = this.SelectedTab.Text;
if (temp[temp.Length - 5] == '*')//有变化才保存
{
//确认是否保存VSD文档到ft_doc_Path
DialogResult response = MessageBox.Show("是否保存故障树" + this.SelectedTab.Name + "到图形文件", "请确认", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (response == System.Windows.Forms.DialogResult.Yes)//确认保存
{
axDrawingControl1.Document.SaveAs(GlobalVariables.ft_doc_Path + axDrawingControl1.Document.Title + ".vsd");//保存当前文档到文件夹
string datetime = DateTime.Now.ToString();//获取当前时间
helpTool.saveVsdDB(axDrawingControl1.Document.Title, datetime);//保存vsd文档到数据库
helpTool.setDatetimeToXml(axDrawingControl1.Document.Title, datetime);//如果信息已存在则将xml中的日期更新,如果不存在直接插入
this.SelectedTab.Text = temp.Substring(0, temp.Length - 5) + " ";//保存后取消星号标志,还原为没变化的时候的样式
}
else if (response == System.Windows.Forms.DialogResult.Cancel)//点击取消或者关闭
{
return;//直接退出,撤销这次关闭程序的事件。
}
}
if (this.TabCount == 1)//是最后一个选项卡,直接关闭父界面,即画图界面
{
father.DisposeForTabControl(true);
}
else//不是最后一个
{
this.TabPages.Remove(this.SelectedTab);
}
}
}
#endregion
#region 右键 选中
else if (e.Button == MouseButtons.Right) // 右键选中
{
for (int i = 0; i < this.TabPages.Count; i++)
{
TabPage tp = this.TabPages[i];
if (this.GetTabRect(i).Contains(new Point(e.X, e.Y)))
{
this.SelectedTab = tp;
break;
}
}
}
#endregion
#region 中键 选中 关闭
else if (e.Button == MouseButtons.Middle)//鼠标中键关闭
{
for (int i = 0; i < this.TabPages.Count; i++)
{
TabPage tp = this.TabPages[i];
if (this.GetTabRect(i).Contains(new Point(e.X, e.Y)))//找到后,关闭
{
this.SelectedTab = tp;
string temp = tp.Text;
if (temp[temp.Length - 5] == '*')//有变化才保存
{
//确认是否保存VSD文档到ft_doc_Path
DialogResult response = MessageBox.Show("是否保存故障树" + this.SelectedTab.Name + "到图形文件", "请确认", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (response == System.Windows.Forms.DialogResult.Yes)//确认保存
{
axDrawingControl1.Document.SaveAs(GlobalVariables.ft_doc_Path + axDrawingControl1.Document.Title + ".vsd");//保存当前文档到文件夹
string datetime = DateTime.Now.ToString();//获取当前时间
helpTool.saveVsdDB(axDrawingControl1.Document.Title, datetime);//保存vsd文档到数据库
helpTool.setDatetimeToXml(axDrawingControl1.Document.Title, datetime);//如果信息已存在则将xml中的日期更新,如果不存在直接插入
this.SelectedTab.Text = temp.Substring(0, temp.Length - 5) + " ";//保存后取消星号标志,还原为没变化的时候的样式
}
else if (response == System.Windows.Forms.DialogResult.Cancel)//点击取消或者关闭
{
return;//直接退出,撤销这次关闭程序的事件。
}
}
if (this.TabCount == 1)//是最后一个选项卡,直接关闭父界面,即画图界面
{
father.DisposeForTabControl(true);
}
else//不是最后一个
{
this.TabPages.Remove(this.SelectedTab);
}
break;
}
}
}
#endregion
}
写完之后如何使用呢???
在你的窗体上拖一个TabControl,然后打开对应窗体代码文件的.Designer.cs文件里找到private void InitializeComponent()方法,然后找到里面对应的TabControl的定义语句即 this.TabControl =。。。。改成this.TabControl = new MyTabControl();如果想传参,就在前面重写MyTabControl时加入带参的构造函数(我的就带有参数)。
值得一提的是.Designer.cs文件里找到private void InitializeComponent()方法都是程序根据你的可视化界面设计自动生成的,所以每次你在可视化的设计环境下重新编辑了,这里就会重新生成,所以你得手动再次改一下this.TabControl = new MyTabControl();
我的程序效果如下


猜你喜欢
- package com.yswc.dao.sign;import java.io.BufferedReader;import java.io
- /** * 循环录像,当内存卡容量少于300M时,自动删除视频列表里面的第一个文件 */private void xunhuanluxian
- 目前做项目中有一个需求是这样的,需要通过java发送url请求,查看该url是否有效,这时我们可以通过获取状态码来判断。try {URL u
- API:即Application programming Interface,应用编程接口。Java中封装了许许多多的API供用户使用,Sc
- Service翻译成中文是服务,熟悉Windows 系统的同学一定很熟悉了。Android里的Service跟Windows里的Servic
- 1.写个Mybatis-plus配置类:是通过 * 实现分页@Configurationpublic class MybatisConfig
- JetBrains JVM Debugger Memory View plugin在我最近的研发活动期间寻找新的工具,以提高我的开发经验,使
- HashMap 在不同的 JDK 版本下的实现是不同的,在 JDK 1.7 时,HashMap 底层是通过数组 + 链表实现的;而在 JDK
- 本文介绍了maven下载jar包改用阿里云maven库的方法,分享给大家,具体如下:修改maven安装路径中conf文件夹下的setting
- 本文实例讲解了Android自动提取短信验证码解决方案,分享给大家供大家参考,具体内容如下<uses-permission andro
- 迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到这个对象
- 将二维数组转化为一维数组1. 为了偷懒所以我写了一个随机生成二维数组的函数/* * 自动创建随机为100以内的二维
- 前言:理论和代码必须结合起来才能真正的掌握一、this概念:this代表着当前对象的引用,也是当前函数所属对象的引用。直白的说,哪个对象调用
- 本文实例讲述了Android 开发使用PopupWindow实现加载等待界面功能。分享给大家供大家参考,具体如下:实现加载等待界面我用了两种
- 这些天忙着刷题,又怕遗忘了spring boot, 所以抽出一点时间折腾折腾,加深点印象。 spring boot 的文件上传与 sprin
- 加载资源文件比较常用的有两种:一、用ClassLoader,说到这里就不得不提一下ClassLoader的分类,java内置的ClassLo
- HashMap和Hashtable的比较是Java面试中的常见问题,用来考验程序员是否能够正确使用集合类以及是否可以随机应变使用多种思路解决
- 背景在工控软件的开发中很多业务场景就是使用图表控件展示设备和工艺参数。如下图案例:实现思路通常简单的做法是使用图表控件实现,常用的图表控件有
- * 的实现使用的模式:代理模式。代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。类似租房的中介。两种 * :(1)jd
- 一:什么是Hystrix在分布式环境中,许多服务依赖项中的一些将不可避免地失败。Hystrix是一个库,通过添加延迟容差和容错逻辑来帮助您控