对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 < (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 < (<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