zoukankan      html  css  js  c++  java
  • 对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
  • 相关阅读:
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 47 全排列 II(二)
    Java实现 LeetCode 47 全排列 II(二)
  • 原文地址:https://www.cnblogs.com/HopeGi/p/4055610.html
Copyright © 2011-2022 走看看