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
  • 相关阅读:
    Ui——创建视图的方法及过程
    iOS设计模式----原型模式
    浅谈OC中排序的方法
    Solid Dominoes Tilings (轮廓线dp打表 + 容器)
    Shell Necklace (dp递推改cdq分治 + fft)
    Rigid Frameworks (画图二分图规律 + DP + 数学组合容斥)
    PowMod (欧拉推式子 + 指数循环节)
    Necklace (全排列 + 匈牙利)
    GCD (RMQ + 二分)
    Game (思维)
  • 原文地址:https://www.cnblogs.com/HopeGi/p/4055610.html
Copyright © 2011-2022 走看看