在重寫TabControl的時候我們最先想到的是設置
this.DrawMode = TabDrawMode.OwnerDrawFixed;
然后重寫
protected override void OnDrawItem(DrawItemEventArgs e) { base.OnDrawItem(e); }
這樣重寫后只是重寫選項卡上的區域,這個區域並不包括邊框,這樣我們所重寫的和邊框不搭調,也無法達到我們想要的功能 。
而更好的方法是重寫整個控件
設置控件由用戶繪制
private void SetStyles() { base.SetStyle( ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); base.UpdateStyles(); }
關鍵的地方在 ControlStyles.UserPaint 設置為true
重寫OnPaint
protected override void OnPaint(PaintEventArgs pe) { base.OnPaint(pe); pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias; pe.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; // pe.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; //繪制背景 Rectangle rect = this.ClientRectangle; pe.Graphics.FillRectangle(new TextureBrush(Properties.Resources.bg), rect); //繪制邊線 int height = this.ItemSize.Height+3; Rectangle r = new Rectangle(DisplayRectangle.X - 1, DisplayRectangle.Y - 1, DisplayRectangle.Width + 1, DisplayRectangle.Height + 1); // pe.Graphics.DrawLine(new Pen(Color.FromArgb(157, 162, 168)), new Point(rect.X, rect.Y + height), new Point(rect.Right, rect.Y + height)); pe.Graphics.DrawRectangle(new Pen(_lineColor), r); //繪制邊框 //繪制標頭 foreach (TabPage tp in this.TabPages) { DrawTabPage(pe.Graphics, this.GetTabRect(this.TabPages.IndexOf(tp)),tp); } }
this.GetTabRect函數可以獲取的標簽的位置,這個為我們重繪標簽提供了很好的幫助
重繪標簽
private void DrawTabPage(Graphics graphics, Rectangle rectangle, TabPage tp) { //繪制底紋 StringFormat sf = new StringFormat(); sf.Trimming = StringTrimming.EllipsisCharacter; sf.FormatFlags = StringFormatFlags.NoWrap; Rectangle rect = new Rectangle (rectangle.X ,rectangle .Y +2,rectangle .Width ,rectangle .Height -2); //標准區域 Rectangle fontRect = new Rectangle(rectangle.X + 5, rectangle.Y+5, rectangle.Width - 10, tp .Font .Height);//文字區域 if (this.SelectedTab.Equals(tp)) { rect = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); fontRect = new Rectangle(rectangle.X + 5, rectangle.Y + 5, rectangle.Width - 25, rectangle.Height - 7); //繪制邊框 graphics.FillPath(new LinearGradientBrush(new Point(rect.X, rect.Y), new Point(rect.X, rect.Y + rect.Height), _ColorActivateA, _ColorActivateB), CreateTabPath(rect)); //填充顏色 graphics.DrawString(tp.Text, tp.Font, new SolidBrush(tp.ForeColor), fontRect, sf); //文字繪制 graphics.DrawPath(new Pen(_lineColor), CreateTabPath(rect));//繪制實邊線 //掩蓋下部的繪制 graphics.DrawLine(new Pen(_ColorActivateB, 3), rect.X, rect.Bottom + 1, rect.X + rect.Width, rect.Bottom + 1); //繪制圖片 Rectangle rectClose = GetCloseRect(rectangle); } else { //繪制邊框 graphics.FillPath(new LinearGradientBrush (new Point (rect .X,rect .Y ),new Point (rect .X,rect .Y +rect .Height ),_ColorDefaultA,_ColorDefaultB), CreateTabPath(rect)); //填充顏色 graphics.DrawString(tp.Text, tp.Font, new SolidBrush(tp.ForeColor), fontRect, sf); //文字繪制 // graphics.DrawPath(new Pen(Color.Wheat, 2), CreateTabPath(rect));//繪制高光邊線 graphics.DrawPath(new Pen(_lineColor), CreateTabPath(rect));//繪制實邊線 }
繪制關閉標簽按鈕
我們給標簽加上了一個鼠標移上去顯示關閉按鈕的功能 重寫OnMouseMove的功能
bool CloseEX = false; protected override void OnMouseMove(MouseEventArgs e) { if (TabPageMouseClose(e.Location) != CloseEX) { CloseEX = !CloseEX; this.Invalidate(); } base.OnMouseMove(e); }
在鼠標移動過快的時候,會導致關閉按鈕沒有刷新,所有我們要在鼠標離開控件的時候讓CloseEx=False並重繪制。
好到這一步我們就完成我我們的繪制工作 。我在繪制的時候使用了漸變畫刷用了5個參數來標識每個指定的顏色
private Color _lineColor = Color.FromArgb(157, 162, 168); //邊線顏色 private Color _ColorDefaultA = Color.FromArgb(231, 231, 231);//默認標簽漸變 a private Color _ColorDefaultB = Color.FromArgb(255, 255, 255);//默認標簽漸變 b private Color _ColorActivateA = Color.FromArgb(184, 203, 217);//點擊漸變a private Color _ColorActivateB = Color.FromArgb(255, 255, 255);//點擊漸變a
