0%

对TabControl的简单优化 - 猴健居士 - 博客园

Excerpt

之前由于忙于赶项目进度而忽视了软件的用户体验,界面挺难看,有一天看见组长优化了某个窗体,让人感觉完全不一样,我也不甘示弱,要把我的程序做顺眼一点才行。我的程序是一个以TabControl为主要容器的窗体,这样的程序窗体在目前广泛使用,谷歌浏览器Chrome,360安全卫士,QQ,鲁大师等。重点是..


  之前由于忙于赶项目进度而忽视了软件的用户体验,界面挺难看,有一天看见组长优化了某个窗体,让人感觉完全不一样,我也不甘示弱,要把我的程序做顺眼一点才行。我的程序是一个以TabControl为主要容器的窗体,这样的程序窗体在目前广泛使用,谷歌浏览器Chrome,360安全卫士,QQ,鲁大师等。

 

重点是头部的TabItem的变迁,从文字到图标结合文字和单纯图标,让TabControl以一种比较友好的形式融入到界面中去。先看看控件的效果

为了让新的TabControl能适应三种情况(文字,图标下衬文字,图标),就定义了如下枚举,

复制代码

1
2
3
4
5
6
<span>1</span>         <span>public</span> <span>enum</span><span> TabTypeEnum
</span><span>2</span> <span> {
</span><span>3</span> <span> ImageText,
</span><span>4</span> <span> Text,
</span><span>5</span> <span> Image,
</span><span>6</span> }

复制代码

同时在新的TabControl类里面定义了对应的属性TabType和私有字段_tabType

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<span>private</span><span> TabTypeEnum _tabType;
</span><span>public</span><span> TabTypeEnum TabType
{
</span><span>get</span> { <span>return</span><span> _tabType; }
</span><span>set</span><span>
{
_tabType </span>=<span> value;
</span><span>if</span> (TabType !=<span> TabTypeEnum.Text)
{
SetStyle(ControlStyles.UserPaint </span>|<span>
ControlStyles.OptimizedDoubleBuffer </span>|<span>
ControlStyles.AllPaintingInWmPaint </span>|<span>
ControlStyles.ResizeRedraw </span>|<span>
ControlStyles.SupportsTransparentBackColor,
</span><span>true</span><span>);
</span><span>base</span><span>.UpdateStyles();

</span><span>this</span>.SizeMode =<span> TabSizeMode.Fixed;


}
</span><span>else</span><span>
{

SizeMode </span>=<span> defaultSizeModel;
</span><span>this</span>.Size =<span> defaultSize;
}
}
}</span>

复制代码

在改变Tab的类型时要额外加一些处理逻辑,如果是Tab包含图标的,肯定要对控件的Style进行设置

复制代码

1
2
3
4
5
SetStyle(ControlStyles.UserPaint |<span>                                           
ControlStyles.OptimizedDoubleBuffer </span>|<span>
ControlStyles.AllPaintingInWmPaint </span>|<br>ControlStyles.ResizeRedraw |<span>
ControlStyles.SupportsTransparentBackColor, </span><span>true</span><span>);
</span><span>base</span>.UpdateStyles();

复制代码

这里设置的都与重绘控件时有关:双缓冲,改变大小则重绘控件。对于单纯图标还有图标+文字,单纯文字这三种方式的Tab大小会有所不同,这个Tab的大小通过ItemSize设置,这里我默认设置了纯文字则按回它初始值的大小,这个初始值在构造函数里获取;图标+文字和纯图标这两种方式在重绘时计算设置。

  描绘控件又是去重写OnPaint方法,这样又用回疏远了很久的GDI+去描绘这个TabItem。这里有三种Tab方式,但着重介绍图标+文字这种方式,Tab选中会有阴影的,阴影可以自己PS一个圆角矩形,我这个是网上抠别人的,这个图片已添加“已有项”的形式添加到项目中,然后生成操作选“嵌入资源”。

然后在构造函数里面以下面的形式获取阴影图片资源

1
backImage = <span>new</span> Bitmap(<span>this</span>.GetType(), <span>"</span><span>select_background.jpg</span><span>"</span>);

在绘图时,先绘阴影,再绘文字,最后绘图标。

获取当前Tab的矩形主要通过TabControl的GetTabRect(int index)方法,通过判断当前的Tab是不是被选中的,来决定绘不绘制阴影

1
2
3
4
<span>if</span> (<span>this</span>.SelectedIndex ==<span> i)
{
e.Graphics.DrawImage(backImage, </span><span>this</span><span>.GetTabRect(i));
}</span>

然后根据Tab文字的Size来决定TabSize,

复制代码

1
2
3
4
5
6
7
<span>if</span> (<span>this</span>.ItemSize.Width &lt; (textSize.Width + <span>this</span>.Padding.X * <span>2</span><span>))
</span><span>this</span>.ItemSize =
<span>new</span> System.Drawing.Size((<span>int</span>)textSize.Width + <span>this</span>.Padding.X * <span>2</span><span>,
</span><span>this</span><span>.ItemSize.Height);
</span><span>if</span> (<span>this</span>.ItemSize.Height &lt; (<span>int</span>)textSize.Height + ImageList.ImageSize.Height + <span>this</span>.Padding.Y * <span>2</span><span>)
</span><span>new</span> System.Drawing.Size(<span>this</span><span>.ItemSize.Width,
(</span><span>int</span>)textSize.Height + ImageList.ImageSize.Height + <span>this</span>.Padding.Y * <span>2</span>);

复制代码

然后按照文字的Size还有Tab矩形的位置大小计算出文字的位置,描绘出文字

复制代码

1
2
3
4
5
6
7
8
9
10
<span>                textPoint.X
</span>= bounds.X + (bounds.Width - textSize.Width) / <span>2</span><span>;
textPoint.Y
</span>= bounds.Bottom - textSize.Height - <span>this</span><span>.Padding.Y;
e.Graphics.DrawString(
</span><span>this</span><span>.TabPages[i].Text,
</span><span>this</span><span>.Font,
SystemBrushes.ControlText,
textPoint.X,
textPoint.Y);</span>

复制代码

最后描绘图标也是结合了图标的Size和Tab的位置与大小来决定图标所在的位置,

1
2
3
4
<span>                    e.Graphics.DrawImage(
icon,
bounds.X </span>+ (bounds.Width - icon.Width) / <span>2</span><span>,
bounds.Top </span>+ <span>this</span>.Padding.Y);

加上了这行代码,能让描绘出来的文字少点锯齿

1
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;  

Tab的描绘就完成了,其余两种Tab只是省去了文字部分或者图标部分的描绘而已,两部分的代码都会在最后列举整个控件源码时顺带列举出来。

         这个控件很大程度上参考了CSDN网友的源码,原本的博文一下子找不出来,要是哪位园友知道的顺带告诉我,我作为参考链接附在文中,谢谢!

ImageTabControl