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= ...
随机推荐
- 5分钟理解Centos7防火墙firewalld
版权声明:本内容为原创内容,转载请声明出处. 原文地址:http://www.excelib.com/article/287/show firewalld简介 Centos7中默认将原来的防火墙ipt ...
- hdu1596 find the safest road - floyd
2017-08-04 14:42:56 writer:pprp 题意: Problem Description XX星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每 ...
- Spring -- spring 中使用jdbc, c3p0连接池, dao概念
1. 示例代码 CustomerDao.java ,dao接口 public interface CustomerDao { public void insertCustomer(Customer ...
- 用java实现单链表
对于一个单链表来说,要求有最基本的数据节点以及一些重要的方法. 方法应该有增删改查.定位.输出.获取链表长度.排序.链表读入.链表输出.下面是我用java写的单链表 public class List ...
- spring mvc:文本框
采用:<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> ...
- 卸载MicrosoftBAF(删除C:\CommonFramework\instdata.dat)
发现有个可疑文件夹 C:\CommonFramework ,而且还会不停的删除创建 C:\CommonFramework\instdata.dat 最后被发现这是必应的一个框架程序在捣鬼,在微软论坛里 ...
- socket长连接和短链接区别
短连接 连接->传输数据->关闭连接 HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束后就中断连接.短连接是指SOCKET连接后发送后接收完数据后马上断 ...
- day5-configparser模块
一.概述 在软件开发过程中,很多时候需要处理配置文件的读取解析和改写,在python中专门处理配置文件的模块就是configpaser了.顾名思义,configpaser就是配置解析器,可用来对符合格 ...
- Ubuntu窗口大小调节方法
Description: 在Vmware Workstation 11上安装了Ubuntu 10.0,画面显示如下所示: Ubuntu系统的屏幕太小.调整方法:调节显示器分辨率即可,下图是将分辨率调节 ...
- get running task , process and service
public class MyActivityManager extends ExpandableListActivity { private static final String NAME = & ...