對TabControl的簡單優化

  以前因爲忙於趕項目進度而忽視了軟件的用戶體驗,界面挺難看,有一天看見組長優化了某個窗體,讓人感受徹底不同,我也不甘示弱,要把個人程序作順眼一點才行。個人程序是一個以TabControl爲主要容器的窗體,這樣的程序窗體在目前普遍使用,谷歌瀏覽器Chrome,360安全衛士,QQ,魯大師等。瀏覽器

 

重點是頭部的TabItem的變遷,從文字到圖標結合文字和單純圖標,讓TabControl以一種比較友好的形式融入到界面中去。先看看控件的效果安全

爲了讓新的TabControl能適應三種狀況(文字,圖標下襯文字,圖標),就定義了以下枚舉,ide

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設置,這裏我默認設置了純文字則按回它初始值的大小,這個初始值在構造函數裏獲取;圖標+文字和純圖標這兩種方式在重繪時計算設置。this

  描繪控件又是去重寫OnPaint方法,這樣又用回疏遠了好久的GDI+去描繪這個TabItem。這裏有三種Tab方式,但着重介紹圖標+文字這種方式,Tab選中會有陰影的,陰影能夠本身PS一個圓角矩形,我這個是網上摳別人的,這個圖片已添加「已有項」的形式添加到項目中,而後生成操做選「嵌入資源」。spa

而後在構造函數裏面如下面的形式獲取陰影圖片資源操作系統

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

 

在繪圖時,先繪陰影,再繪文字,最後繪圖標。code

獲取當前Tab的矩形主要經過TabControl的GetTabRect(int index)方法,經過判斷當前的Tab是否是被選中的,來決定繪不繪製陰影blog

                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
相關文章
相關標籤/搜索