Winform 自定义TabControl实现浏览器标签
作者:Gavin(daisong.michelangelo@gmail.com)
时间: Nov, 2015
封面图片为Gavin原创,请勿未经允许私自引
最近因为工作需要,要做一个桌面浏览器,和大多数浏览器一样,我的这个浏览器也需要有标签栏,效果就像这样:目标效果图
在网上查了很多资料,大多数做法都是自定义Winform中TabControl控件,具体的做法有多种。
首先让我们来见识一下winform原生的TabControl是什么样子的:
怎么样,有没有让你有种思考人生的冲动?
下面我们来分析怎么将它改造成我们想要的模样
TabControl有由一个个TabPage组成,每个TabPage有一个TabItem(也就是页签)
让我们从这个页签开始,它由以下三部分组成:
- 标签页左边是一个图标
- 中间是网页的Title
- 右边是标签的关闭按钮
要实现这三个部分,我们可以重写TabControl.DrawItem 事件,在这之前我们当然要继承Winform 的TabControl 组件:
public partial class TabControl1 : TabControl
然后还要记得将DrawMode 设置成 TabDrawMode.OwnerDrawFixed,这样我们就可以自己画TabItem了,否则你在DrawItem里面干的事可就白干了。
然后,我们就可以重写DrawItem事件,开始画也签了
this.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.MainTab_DrawItem);
首先,我们可以先设置标签页的背景,而且标签在选中和未选中的时候背景是不一样的。
// 获取当前选项卡区域
Rectangle bounds = GetTabRect(e.Index);
Brush br = SystemBrushes.ActiveCaptionText;
if (e.Index == this.SelectedIndex) //当前选中的Tab页,设置不同的样式以示选中
{
e.Graphics.FillRectangle(Brushes.White, bounds); //改变选中选项卡标签的背景色
}
else
{
e.Graphics.FillRectangle(Brushes.DarkRed, bounds); //改变非选中的选项卡标签的背景色
br = SystemBrushes.GrayText; //置灰非选中项
}
注意,一定要先画背景,在画其他的东西,不然后画背景会将之前画的东西擦除掉。
接着我们就可以来画图标了,TabControl 有一个ImageList可以存放图片,可以通过key和index获取到。原生的TabControl已经实现了这个功能,但是我们重写了整个TabItem的绘制方法,所以我们还是要自己实现。
//绘制图标
if (this.ImageList != null)
{
int index = this.TabPages[e.Index].ImageIndex;
string key = this.TabPages[e.Index].ImageKey;
Image icon = new Bitmap(icoSize, icoSize);
if (index > -1)
{
icon = this.ImageList.Images[index];
}
if (!string.IsNullOrEmpty(key))
{
icon = this.ImageList.Images[key];
}
e.Graphics.DrawImage(icon, bounds.X + startX, bounds.Top + 2);
}
好了,我们快要完成了,Graphics有绘制各种形状的方法,参数大多含有坐标,坐标控制就不多说了,MSDN里的方法说的很清楚了。
接下来,我们要画文字了,很简单,TabPages[i].Text就是我们的Title
e.Graphics.DrawString(this.TabPages[i].Text, font, br, bounds.X + startX, bounds.Y + 6);
最后,我们还是一样的方法画出关闭按钮。closeImage可以先导入到资源文件
bounds.Offset(bounds.Width - (CLOSE_SIZE + 5), 2);
e.Graphics.DrawImage(closeImage, bounds.X, bounds.Y);
好了,页签的外观我们已经大工告成了,接下来我们要响应关闭按钮来关闭页签。
方法是监听鼠标点击事件,如果点击区域是在我们画关闭按钮的区域呢,我们就冲tabPages中将这个Page移除。
//计算关闭区域
Rectangle bounds = this.GetTabRect(this.SelectedIndex);
bounds.Offset(bounds.Width - (CLOSE_SIZE + 5), 2);
bounds.Width = CLOSE_SIZE;
bounds.Height = CLOSE_SIZE;
//如果鼠标在区域内就关闭选项卡
bool isClose = x > bounds.X && x < bounds.Right
&& y > bounds.Y && y < bounds.Bottom;
if (isClose == true)
{
int index = this.SelectedIndex;
TabPage tab = this.SelectedTab;
this.TabPages.Remove(tab);
tab.Dispose();
}
好了,看来我们已经完美地做出了一个美观的TabItem了,如果你没有别的需要的话,这样的组件就可以使用了。
但如我之前所说,实现方法有多种,因为需求总是在变,所以我们还是需要一种更全面的方法。
如果我需要改变整个TabControl 的背景色透明要怎么办呢?
仅仅重写DrawTabItem是远远不够的。
好了,下面进入今天的主题,怎么重写TabControl的OnPaint()方法来实现我们之前所实现的功能。
首先,我们当然要继承TabControl,还要设置几个属性
this.SetStyle(
ControlStyles.UserPaint | // 控件将自行绘制,而不是通过操作系统来绘制
ControlStyles.OptimizedDoubleBuffer | // 该控件首先在缓冲区中绘制,而不是直接绘制到屏幕上,这样可以减少闪烁
ControlStyles.AllPaintingInWmPaint | // 控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁
ControlStyles.ResizeRedraw | // 在调整控件大小时重绘控件
ControlStyles.SupportsTransparentBackColor, // 控件接受 alpha 组件小于 255 的 BackColor 以模拟透明
true); // 设置以上值为 true
this.UpdateStyles();
最终要的一个就是要设置ControlStyles.UserPaint 为True,不然你就思考人生吧!但是设置了这个属性我们就要告别过去,从一张白纸开始了,当然这也意味着我们就可以尽情发挥了。
首先,我们就可以重写OnPaint方法了,这里我们绘制背景就很方便了,只要画一张图片就好了。
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle rec = this.ClientRectangle; // 获取TabControl主控件的工作区域
Image backImage = Properties.Resources.bgImage; //获取背景图片,我的背景图片在项目资源文件中。
e.Graphics.DrawImage(backImage, 0, 0, this.Width, this.Height); //绘制主控件的背景
//绘制标签样式
for (int i = 0; i < this.TabPages.Count; i++)
{
//....这里和绘制上面的标签页类似
}
}
好了,先写到这吧,一个简单的自定义TabControl就实现了。
参考资料:
Winform 自定义TabControl实现浏览器标签的更多相关文章
- [转]一步一步玩控件:自定义TabControl——从山寨Safari开始
作者:野比 (conmajia@gmail.com) 时间:May, 2012 封面图片为野比原创,请勿未经允许私自引用 #1-1 嗯,各位,又是我,生物钟颠倒的家伙. 今天我要山寨的是大名鼎鼎的Ap ...
- 一步一步玩控件:自定义TabControl——从山寨Safari开始
作者:野比 (conmajia@gmail.com) 时间:May, 2012 封面图片为野比原创,请勿未经允许私自引用 #1-1 嗯,各位,又是我,生物钟颠倒的家伙. 今天我要山寨的是大名鼎鼎的Ap ...
- WPF自定义TabControl样式
WPF自定义TabControl,TabControl美化 XAML代码: <TabControl x:Class="SunCreate.Common.Controls.TabCont ...
- DevExpress navBarControl 和 xtraTabbedMdiManager实现浏览器标签页效果
一:navBarControl 属性设置 工具箱中的Navigation & Layout选项卡下找到NavBarControl,拖到窗体中 工具箱中添加2个imageCollection.分 ...
- [转] WinForm自定义函数FindControl实现按名称查找控件
原文地址 WinForm自定义函数FindControl实现按名称查找控件 本文所述实例实现WinForm自定义函数FindControl实现按名称查找控件的功能,在C#程序开发中有一定的实用价值. ...
- js基础--浏览器标签页隐藏或显示状态 visibility详解
欢迎访问我的个人博客:http://www.xiaolongwu.cn 前言 在工作中我们可能会遇到这样的需求,当浏览器切换到别的标签页或着最小化时,我们需要暂停页面上正在播放的视频或者音乐,这个需求 ...
- selenium WebDriver 对浏览器标签页的切换
关于selenium WebDriver 对浏览器标签页的切换,现在的市面上最新的浏览器,当点击一个链接打开一个新的页面都是在浏览器中打开一个标签页,而selenium只能对窗口进行切换的方法,只能操 ...
- Django 自定义 过滤器和模板标签
代码布局(自定义的代码,放在哪里) 二种方式:1. 某个app特有的 -app 目录下,templatetags 文件夹 ** 必需是这个名称的包(目录中有__init__.py文件) -再到 ...
- Django框架之【自定义模板过滤器与标签】
本文在我的微信公众号的链接:https://mp.weixin.qq.com/s?__biz=MzU5NTU5MjcwNw==&mid=2247483674&idx=1&sn= ...
随机推荐
- 理解Java中字符流与字节流的区别(转)
1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...
- Linux软件安装(二)
1. 安装软件时,如果依赖的文件是 .so 类型的文件(so文件是谋个文件的小功能模块,如果php.ini中设置的模块引用就是 .so文件) ,这时被依赖的软件要安装完整的软件,一般可以根据 .so ...
- 第一章 Burp Suite 安装和环境配置
Burp Suite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击.在渗透测试中,我们使用Burp Suite将使得测试工作变得更 ...
- Django进阶Model篇008 - 使用原生sql
注意:使用原生sql的方式主要目的是解决一些很复杂的sql不能用ORM的方式写出的问题. 一.extra:结果集修改器-一种提供额外查询参数的机制 二.执行原始sql并返回模型实例 三.直接执行自定义 ...
- java 多媒体发送邮件
import java.util.Properties; import javax.mail.Address; import javax.mail.BodyPart; import javax.mai ...
- vue-cli 脚手架项目简介(一) - package.json
vue-cli是用来生成 vue项目的命令行工具,它的使用方法是这样的: vue init <template-name> <project-name>第二个参数 templa ...
- mysql 字段属性 与 排序
mysql中常见的数据类型:varchar(n).float.int(n).bigint(n).date.datetime.text 字段属性 默认值:DEFAULT '默认值' 非空:NOT NUL ...
- C#学习历程(二)[基础知识]
c#中类型的转换 1.Convert.ToInt32(string s) 这个方法的返回值是int类型,要用int类型的变量接收 如: string strNum=Console.ReadLine() ...
- 简单使用JDOM解析XML
原文:http://liuwentao.iteye.com/blog/59978 使用JDOM解析XML一.前言JDOM是Breet Mclaughlin和Jason Hunter两大Java高手的创 ...
- 简要谈谈javascript bind 方法
最近去参加了场面试,跟面试官聊了很多JS基础上的东西,其中有个问题是谈谈对apply.call.bind的理解和区别.顿时一愣,apply.call我知道,经常用的东西,bind是什么鬼!!!好像见过 ...