对TabControl的简单优化

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

 

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

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

1         public enum TabTypeEnum

2         {

3             ImageText,

4             Text,

5             Image,

6         }

 

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

        private TabTypeEnum _tabType;

        public TabTypeEnum TabType

        {

            get { return _tabType; }

            set

            {

                _tabType = value;

                if (TabType != TabTypeEnum.Text)

                {

                    SetStyle(ControlStyles.UserPaint |                      

                     ControlStyles.OptimizedDoubleBuffer |            

                     ControlStyles.AllPaintingInWmPaint |          

                     ControlStyles.ResizeRedraw |                   

                     ControlStyles.SupportsTransparentBackColor,    

                     true);

                    base.UpdateStyles();



                    this.SizeMode = TabSizeMode.Fixed;





                }

                else

                {



                    SizeMode = defaultSizeModel;

                    this.Size = defaultSize;

                }

            }

        }

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

SetStyle(ControlStyles.UserPaint |                                           

ControlStyles.OptimizedDoubleBuffer |                               

ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); base.UpdateStyles();

 

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

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

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

backImage = new Bitmap(this.GetType(), "select_background.jpg");

 

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

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

                if (this.SelectedIndex == i)

                {

                    e.Graphics.DrawImage(backImage, this.GetTabRect(i));

                }

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

                if (this.ItemSize.Width < (textSize.Width + this.Padding.X * 2))

                    this.ItemSize =

                        new System.Drawing.Size((int)textSize.Width + this.Padding.X * 2,

                            this.ItemSize.Height);

                if (this.ItemSize.Height < (int)textSize.Height + ImageList.ImageSize.Height + this.Padding.Y * 2)

                    new System.Drawing.Size(this.ItemSize.Width,

                        (int)textSize.Height + ImageList.ImageSize.Height + this.Padding.Y * 2);

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

                textPoint.X

                    = bounds.X + (bounds.Width - textSize.Width) / 2;

                textPoint.Y

                    = bounds.Bottom - textSize.Height - this.Padding.Y;

                e.Graphics.DrawString(

                    this.TabPages[i].Text,

                    this.Font,

                    SystemBrushes.ControlText,    

                    textPoint.X,

                    textPoint.Y);

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

                    e.Graphics.DrawImage(

                        icon,

                        bounds.X + (bounds.Width - icon.Width) / 2,

                        bounds.Top + this.Padding.Y);

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

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

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

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

  1     class ImageTabControl:TabControl

  2     {

  3         public enum TabTypeEnum

  4         {

  5             ImageText,

  6             Text,

  7             Image,

  8         }

  9 

 10         Image backImage;

 11         Size defaultSize;

 12         TabSizeMode defaultSizeModel;

 13 

 14         public ImageTabControl()

 15         {

 16             defaultSize = this.ItemSize;

 17             defaultSizeModel = this.SizeMode;

 18 

 19             this.TabType = TabTypeEnum.ImageText;

 20             backImage = new Bitmap(this.GetType(), "select_background.jpg");

 21         }

 22 

 23         private TabTypeEnum _tabType;

 24         public TabTypeEnum TabType

 25         {

 26             get { return _tabType; }

 27             set

 28             {

 29                 _tabType = value;

 30                 if (TabType != TabTypeEnum.Text)

 31                 {

 32                     SetStyle(ControlStyles.UserPaint |                      // 控件将自行绘制,而不是通过操作系统来绘制  

 33                      ControlStyles.OptimizedDoubleBuffer |          // 该控件首先在缓冲区中绘制,而不是直接绘制到屏幕上,这样可以减少闪烁  

 34                      ControlStyles.AllPaintingInWmPaint |           // 控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁  

 35                      ControlStyles.ResizeRedraw |                   // 在调整控件大小时重绘控件  

 36                      ControlStyles.SupportsTransparentBackColor,    // 控件接受 alpha 组件小于 255 的 BackColor 以模拟透明  

 37                      true);

 38                     base.UpdateStyles();

 39 

 40                     this.SizeMode = TabSizeMode.Fixed;

 41                 }

 42                 else

 43                 {

 44 

 45                     SizeMode = defaultSizeModel;

 46                     this.Size = defaultSize;

 47                 }

 48             }

 49         }

 50 

 51         protected override void OnPaint(PaintEventArgs e)

 52         {

 53             base.OnPaint(e);

 54 

 55             if (TabType == TabTypeEnum.ImageText)

 56                 DrawImageTextItem(e);

 57             else if (TabType == TabTypeEnum.Image)

 58                 DrawImageItem(e);

 59             else if (TabType == TabTypeEnum.Text)

 60                 DrawTextItem(e);

 61         }

 62 

 63         protected virtual void DrawImageTextItem(PaintEventArgs e)

 64         {

 65             for (int i = 0; i < this.TabCount; i++)

 66             {

 67                 //e.Graphics.DrawRectangle(Pens.Red, this.GetTabRect(i));

 68                 if (this.SelectedIndex == i)

 69                 {

 70                     e.Graphics.DrawImage(backImage, this.GetTabRect(i));

 71                 }

 72 

 73                 // Calculate text position  

 74                 Rectangle bounds = this.GetTabRect(i);

 75                 PointF textPoint = new PointF();

 76                 SizeF textSize = TextRenderer.MeasureText(this.TabPages[i].Text, this.Font);

 77 

 78                 if (this.ItemSize.Width < (textSize.Width + this.Padding.X * 2))

 79                     this.ItemSize =

 80                         new System.Drawing.Size((int)textSize.Width + this.Padding.X * 2,

 81                             this.ItemSize.Height);

 82                 if (this.ItemSize.Height < (int)textSize.Height + ImageList.ImageSize.Height + this.Padding.Y * 2)

 83                     new System.Drawing.Size(this.ItemSize.Width,

 84                         (int)textSize.Height + ImageList.ImageSize.Height + this.Padding.Y * 2);

 85 

 86                 // 注意要加上每个标签的左偏移量X  

 87                 textPoint.X

 88                     = bounds.X + (bounds.Width - textSize.Width) / 2;

 89                 textPoint.Y

 90                     = bounds.Bottom - textSize.Height - this.Padding.Y;

 91 

 92                 // Draw highlights  

 93                 e.Graphics.DrawString(

 94                     this.TabPages[i].Text,

 95                     this.Font,

 96                     SystemBrushes.ControlLightLight,    // 高光颜色  

 97                     textPoint.X,

 98                     textPoint.Y);

 99 

100                 // 绘制正常文字  

101                 textPoint.Y--;

102                 e.Graphics.DrawString(

103                     this.TabPages[i].Text,

104                     this.Font,

105                     SystemBrushes.ControlText,    // 正常颜色  

106                     textPoint.X,

107                     textPoint.Y);

108 

109 

110                 if (this.ImageList != null)

111                 {

112                     int index = this.TabPages[i].ImageIndex;

113                     string key = this.TabPages[i].ImageKey;

114                     Image icon = new Bitmap(1, 1);

115 

116                     if (index > -1)

117                     {

118                         icon = this.ImageList.Images[index];

119                     }

120                     if (!string.IsNullOrEmpty(key))

121                     {

122                         icon = this.ImageList.Images[key];

123                     }

124                     e.Graphics.DrawImage(

125                         icon,

126                         bounds.X + (bounds.Width - icon.Width) / 2,

127                         bounds.Top + this.Padding.Y);

128                 }

129             }

130 

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

132         }

133 

134         protected virtual void DrawImageItem(PaintEventArgs e)

135         {

136             for (int i = 0; i < this.TabPages.Count; i++)

137             {

138                 if (i == this.SelectedIndex)

139                 {

140                     e.Graphics.DrawImage(backImage, this.GetTabRect(i));

141                 }

142 

143                 RectangleF itemRec = this.GetTabRect(i);

144 

145                 if (ImageList != null)

146                 { 

147                     int imageIndex=this.TabPages[i].ImageIndex;

148                     string imageKey=this.TabPages[i].ImageKey;

149                     Image ico=new Bitmap(1,1);

150                     if (imageIndex >= 0)

151                         ico = this.ImageList.Images[i];

152                     if (!string.IsNullOrEmpty(imageKey))

153                         ico = this.ImageList.Images[imageKey];

154 

155                     if (this.ItemSize.Height < ImageList.ImageSize.Height + this.Padding.Y * 2)

156                         this.ItemSize = new System.Drawing.Size(this.ItemSize.Width,

157                             ImageList.ImageSize.Height + this.Padding.Y * 2);

158                     if (this.ItemSize.Width < ImageList.ImageSize.Width + this.Padding.X * 2)

159                         this.ItemSize = new System.Drawing.Size(ImageList.ImageSize.Width + this.Padding.X * 2,

160                             this.ItemSize.Height);

161 

162                     e.Graphics.DrawImage(ico, itemRec.X + (itemRec.Width - ico.Width) / 2, itemRec.Y + this.Padding.Y);

163                 }

164             }

165         }

166 

167         protected virtual void DrawTextItem(PaintEventArgs e)

168         {

169             for (int i = 0; i < this.TabCount; i++)

170             {

171                 //e.Graphics.DrawRectangle(Pens.Red, this.GetTabRect(i));

172                 if (this.SelectedIndex == i)

173                 {

174                     e.Graphics.DrawImage(backImage, this.GetTabRect(i));

175                 }

176 

177                 // Calculate text position  

178                 Rectangle bounds = this.GetTabRect(i);

179                 PointF textPoint = new PointF();

180                 SizeF textSize = TextRenderer.MeasureText(this.TabPages[i].Text, this.Font);

181 

182                 // 注意要加上每个标签的左偏移量X  

183                 textPoint.X

184                     = bounds.X + (bounds.Width - textSize.Width) / 2;

185                 textPoint.Y

186                     = bounds.Y+(bounds.Height-textSize.Height)/2;

187 

188                 // Draw highlights  

189                 e.Graphics.DrawString(

190                     this.TabPages[i].Text,

191                     this.Font,

192                     SystemBrushes.ControlLightLight,    // 高光颜色  

193                     textPoint.X,

194                     textPoint.Y);

195 

196                 // 绘制正常文字  

197                 textPoint.Y--;

198                 e.Graphics.DrawString(

199                     this.TabPages[i].Text,

200                     this.Font,

201                     SystemBrushes.ControlText,    // 正常颜色  

202                     textPoint.X,

203                     textPoint.Y);

204 

205             }

206         }

207     }
ImageTabControl

 

你可能感兴趣的:(tab)