前提 入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。 開源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control 如果覺得寫的還行,請點個 star 支持一下吧 歡迎前來交流探討: 企鵝群568015492 目錄 ...
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。
開源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
如果覺得寫的還行,請點個 star 支持一下吧
目錄
https://www.cnblogs.com/bfyx/p/11364884.html
準備工作
此控制項在https://www.cnblogs.com/belx/articles/9188577.html基礎上調整修改,特此感謝
開始
添加一個用戶組件,命名TabControlExt,繼承自TabControl
幾個重寫屬性
1 private Color _backColor = Color.White; 2 [Browsable(true)] 3 [EditorBrowsable(EditorBrowsableState.Always)] 4 [DefaultValue(typeof(Color), "White")] 5 public override Color BackColor 6 { 7 get { return _backColor; } 8 set 9 { 10 _backColor = value; 11 base.Invalidate(true); 12 } 13 } 14 15 private Color _borderColor = Color.FromArgb(232, 232, 232); 16 [DefaultValue(typeof(Color), "232, 232, 232")] 17 [Description("TabContorl邊框色")] 18 public Color BorderColor 19 { 20 get { return _borderColor; } 21 set 22 { 23 _borderColor = value; 24 base.Invalidate(true); 25 } 26 } 27 28 private Color _headSelectedBackColor = Color.FromArgb(255, 85, 51); 29 [DefaultValue(typeof(Color), "255, 85, 51")] 30 [Description("TabPage頭部選中後的背景顏色")] 31 public Color HeadSelectedBackColor 32 { 33 get { return _headSelectedBackColor; } 34 set { _headSelectedBackColor = value; } 35 } 36 37 private Color _headSelectedBorderColor = Color.FromArgb(232, 232, 232); 38 [DefaultValue(typeof(Color), "232, 232, 232")] 39 [Description("TabPage頭部選中後的邊框顏色")] 40 public Color HeadSelectedBorderColor 41 { 42 get { return _headSelectedBorderColor; } 43 set { _headSelectedBorderColor = value; } 44 } 45 46 private Color _headerBackColor = Color.White; 47 [DefaultValue(typeof(Color), "White")] 48 [Description("TabPage頭部預設背景顏色")] 49 public Color HeaderBackColor 50 { 51 get { return _headerBackColor; } 52 set { _headerBackColor = value; } 53 }
重寫背景
1 protected override void OnPaintBackground(PaintEventArgs pevent) 2 { 3 if (this.DesignMode == true) 4 { 5 LinearGradientBrush backBrush = new LinearGradientBrush( 6 this.Bounds, 7 SystemColors.ControlLightLight, 8 SystemColors.ControlLight, 9 LinearGradientMode.Vertical); 10 pevent.Graphics.FillRectangle(backBrush, this.Bounds); 11 backBrush.Dispose(); 12 } 13 else 14 { 15 this.PaintTransparentBackground(pevent.Graphics, this.ClientRectangle); 16 } 17 } 18 /// <summary> 19 /// TabContorl 背景色設置 20 /// </summary> 21 /// <param name="g"></param> 22 /// <param name="clipRect"></param> 23 protected void PaintTransparentBackground(Graphics g, Rectangle clipRect) 24 { 25 if ((this.Parent != null)) 26 { 27 clipRect.Offset(this.Location); 28 PaintEventArgs e = new PaintEventArgs(g, clipRect); 29 GraphicsState state = g.Save(); 30 g.SmoothingMode = SmoothingMode.HighSpeed; 31 try 32 { 33 g.TranslateTransform((float)-this.Location.X, (float)-this.Location.Y); 34 this.InvokePaintBackground(this.Parent, e); 35 this.InvokePaint(this.Parent, e); 36 } 37 finally 38 { 39 g.Restore(state); 40 clipRect.Offset(-this.Location.X, -this.Location.Y); 41 //新加片段,待測試 42 using (SolidBrush brush = new SolidBrush(_backColor)) 43 { 44 clipRect.Inflate(1, 1); 45 g.FillRectangle(brush, clipRect); 46 } 47 } 48 } 49 else 50 { 51 System.Drawing.Drawing2D.LinearGradientBrush backBrush = new System.Drawing.Drawing2D.LinearGradientBrush(this.Bounds, SystemColors.ControlLightLight, SystemColors.ControlLight, System.Drawing.Drawing2D.LinearGradientMode.Vertical); 52 g.FillRectangle(backBrush, this.Bounds); 53 backBrush.Dispose(); 54 } 55 }
重繪
1 protected override void OnPaint(PaintEventArgs e) 2 { 3 // Paint the Background 4 base.OnPaint(e); 5 this.PaintTransparentBackground(e.Graphics, this.ClientRectangle); 6 this.PaintAllTheTabs(e); 7 this.PaintTheTabPageBorder(e); 8 this.PaintTheSelectedTab(e); 9 }
輔助函數
1 private void PaintAllTheTabs(System.Windows.Forms.PaintEventArgs e) 2 { 3 if (this.TabCount > 0) 4 { 5 for (int index = 0; index < this.TabCount; index++) 6 { 7 this.PaintTab(e, index); 8 } 9 } 10 } 11 12 private void PaintTab(System.Windows.Forms.PaintEventArgs e, int index) 13 { 14 GraphicsPath path = this.GetTabPath(index); 15 this.PaintTabBackground(e.Graphics, index, path); 16 this.PaintTabBorder(e.Graphics, index, path); 17 this.PaintTabText(e.Graphics, index); 18 this.PaintTabImage(e.Graphics, index); 19 } 20 21 /// <summary> 22 /// 設置選項卡頭部顏色 23 /// </summary> 24 /// <param name="graph"></param> 25 /// <param name="index"></param> 26 /// <param name="path"></param> 27 private void PaintTabBackground(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path) 28 { 29 Rectangle rect = this.GetTabRect(index); 30 System.Drawing.Brush buttonBrush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, _headerBackColor, _headerBackColor, LinearGradientMode.Vertical); //非選中時候的 TabPage 頁頭部背景色 31 graph.FillPath(buttonBrush, path); 32 //if (index == this.SelectedIndex) 33 //{ 34 // //buttonBrush = new System.Drawing.SolidBrush(_headSelectedBackColor); 35 // graph.DrawLine(new Pen(_headerBackColor), rect.Right+2, rect.Bottom, rect.Left + 1, rect.Bottom); 36 //} 37 buttonBrush.Dispose(); 38 } 39 40 /// <summary> 41 /// 設置選項卡頭部邊框色 42 /// </summary> 43 /// <param name="graph"></param> 44 /// <param name="index"></param> 45 /// <param name="path"></param> 46 private void PaintTabBorder(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path) 47 { 48 Pen borderPen = new Pen(_borderColor);// TabPage 非選中時候的 TabPage 頭部邊框色 49 if (index == this.SelectedIndex) 50 { 51 borderPen = new Pen(_headSelectedBorderColor); // TabPage 選中後的 TabPage 頭部邊框色 52 } 53 graph.DrawPath(borderPen, path); 54 borderPen.Dispose(); 55 } 56 57 private void PaintTabImage(System.Drawing.Graphics g, int index) 58 { 59 Image tabImage = null; 60 if (this.TabPages[index].ImageIndex > -1 && this.ImageList != null) 61 { 62 tabImage = this.ImageList.Images[this.TabPages[index].ImageIndex]; 63 } 64 else if (this.TabPages[index].ImageKey.Trim().Length > 0 && this.ImageList != null) 65 { 66 tabImage = this.ImageList.Images[this.TabPages[index].ImageKey]; 67 } 68 if (tabImage != null) 69 { 70 Rectangle rect = this.GetTabRect(index); 71 g.DrawImage(tabImage, rect.Right - rect.Height - 4, 4, rect.Height - 2, rect.Height - 2); 72 } 73 } 74 75 private void PaintTabText(System.Drawing.Graphics graph, int index) 76 { 77 string tabtext = this.TabPages[index].Text; 78 79 System.Drawing.StringFormat format = new System.Drawing.StringFormat(); 80 format.Alignment = StringAlignment.Near; 81 format.LineAlignment = StringAlignment.Center; 82 format.Trimming = StringTrimming.EllipsisCharacter; 83 84 Brush forebrush = null; 85 86 if (this.TabPages[index].Enabled == false) 87 { 88 forebrush = SystemBrushes.ControlDark; 89 } 90 else 91 { 92 forebrush = SystemBrushes.ControlText; 93 } 94 95 Font tabFont = this.Font; 96 if (index == this.SelectedIndex) 97 { 98 if (this.TabPages[index].Enabled != false) 99 { 100 forebrush = new SolidBrush(_headSelectedBackColor); 101 } 102 } 103 104 Rectangle rect = this.GetTabRect(index); 105 106 var txtSize = ControlHelper.GetStringWidth(tabtext, graph, tabFont); 107 Rectangle rect2 = new Rectangle(rect.Left + (rect.Width - txtSize) / 2 - 1, rect.Top, rect.Width, rect.Height); 108 109 graph.DrawString(tabtext, tabFont, forebrush, rect2, format); 110 } 111 112 /// <summary> 113 /// 設置 TabPage 內容頁邊框色 114 /// </summary> 115 /// <param name="e"></param> 116 private void PaintTheTabPageBorder(System.Windows.Forms.PaintEventArgs e) 117 { 118 if (this.TabCount > 0) 119 { 120 Rectangle borderRect = this.TabPages[0].Bounds; 121 //borderRect.Inflate(1, 1); 122 Rectangle rect = new Rectangle(borderRect.X - 2, borderRect.Y-1, borderRect.Width + 5, borderRect.Height+2); 123 ControlPaint.DrawBorder(e.Graphics, rect, this.BorderColor, ButtonBorderStyle.Solid); 124 } 125 } 126 127 /// <summary> 128 /// // TabPage 頁頭部間隔色 129 /// </summary> 130 /// <param name="e"></param> 131 private void PaintTheSelectedTab(System.Windows.Forms.PaintEventArgs e) 132 { 133 if (this.SelectedIndex == -1) 134 return; 135 Rectangle selrect; 136 int selrectRight = 0; 137 selrect = this.GetTabRect(this.SelectedIndex); 138 selrectRight = selrect.Right; 139 e.Graphics.DrawLine(new Pen(_headSelectedBackColor), selrect.Left, selrect.Bottom + 1, selrectRight, selrect.Bottom + 1); 140 } 141 142 private GraphicsPath GetTabPath(int index) 143 { 144 System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath(); 145 path.Reset(); 146 147 Rectangle rect = this.GetTabRect(index); 148 149 switch (Alignment) 150 { 151 case TabAlignment.Top: 152 153 break; 154 case TabAlignment.Bottom: 155 156 break; 157 case TabAlignment.Left: 158 159 break; 160 case TabAlignment.Right: 161 162 break; 163 } 164 165 path.AddLine(rect.Left, rect.Top, rect.Left, rect.Bottom + 1); 166 path.AddLine(rect.Left, rect.Top, rect.Right , rect.Top); 167 path.AddLine(rect.Right , rect.Top, rect.Right , rect.Bottom + 1); 168 path.AddLine(rect.Right , rect.Bottom + 1, rect.Left, rect.Bottom + 1); 169 170 return path; 171 }
2個重寫函數處理字體相關
1 [DllImport("user32.dll")] 2 private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); 3 4 private const int WM_SETFONT = 0x30; 5 private const int WM_FONTCHANGE = 0x1d; 6 7 protected override void OnCreateControl() 8 { 9 base.OnCreateControl(); 10 this.OnFontChanged(EventArgs.Empty); 11 } 12 13 protected override void OnFontChanged(EventArgs e) 14 { 15 base.OnFontChanged(e); 16 IntPtr hFont = this.Font.ToHfont(); 17 SendMessage(this.Handle, WM_SETFONT, hFont, (IntPtr)(-1)); 18 SendMessage(this.Handle, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero); 19 this.UpdateStyles(); 20 }
完整代碼
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Diagnostics; 5 using System.Drawing; 6 using System.Drawing.Drawing2D; 7 using System.Linq; 8 using System.Runtime.InteropServices; 9 using System.Text; 10 using System.Windows.Forms; 11 12 namespace HZH_Controls.Controls 13 { 14 public class TabControlExt : TabControl 15 { 16 public TabControlExt() 17 : base() 18 { 19 SetStyles(); 20 this.Multiline = true; 21 this.ItemSize = new Size(this.ItemSize.Width, 50); 22 } 23 24 private void SetStyles() 25 { 26 base.SetStyle( 27 ControlStyles.UserPaint | 28 ControlStyles.DoubleBuffer | 29 ControlStyles.OptimizedDoubleBuffer | 30 ControlStyles.AllPaintingInWmPaint | 31 ControlStyles.ResizeRedraw | 32 ControlStyles.SupportsTransparentBackColor, true); 33 base.UpdateStyles(); 34 } 35 36 private Color _backColor = Color.White; 37 [Browsable(true)] 38 [EditorBrowsable(EditorBrowsableState.Always)] 39 [DefaultValue(typeof(Color), "White")] 40 public override Color BackColor 41 { 42 get { return _backColor; } 43 set 44 { 45 _backColor = value; 46 base.Invalidate(true); 47 } 48 } 49 50 private Color _borderColor = Color.FromArgb(232, 232, 232); 51 [DefaultValue(typeof(Color), "232, 232, 232")] 52 [Description("TabContorl邊框色")] 53 public Color BorderColor 54 { 55 get { return _borderColor; } 56 set 57 { 58 _borderColor = value; 59 base.Invalidate(true); 60 } 61 } 62 63 private Color _headSelectedBackColor = Color.FromArgb(255, 85, 51); 64 [DefaultValue(typeof(Color), "255, 85, 51")] 65 [Description("TabPage頭部選中後的背景顏色")] 66 public Color HeadSelectedBackColor 67 { 68 get { return _headSelectedBackColor; } 69 set { _headSelectedBackColor = value; } 70 } 71 72 private Color _headSelectedBorderColor = Color.FromArgb(232, 232, 232); 73 [DefaultValue(typeof(Color), "232, 232, 232")] 74 [Description("TabPage頭部選中後的邊框顏色")] 75 public Color HeadSelectedBorderColor 76 { 77 get { return _headSelectedBorderColor; } 78 set { _headSelectedBorderColor = value; } 79 } 80 81 private Color _headerBackColor = Color.White; 82 [DefaultValue(typeof(Color), "White")] 83 [Description("TabPage頭部預設背景顏色")] 84 public Color HeaderBackColor 85 { 86 get { return _headerBackColor; } 87 set { _headerBackColor = value; } 88 } 89 90 protected override void OnPaintBackground(PaintEventArgs pevent) 91 { 92 if (this.DesignMode == true) 93 { 94 LinearGradientBrush backBrush = new LinearGradientBrush( 95 this.Bounds, 96 SystemColors.ControlLightLight, 97 SystemColors.ControlLight, 98 LinearGradientMode.Vertical); 99 pevent.Graphics.FillRectangle(backBrush, this.Bounds); 100 backBrush.Dispose(); 101 } 102 else 103 { 104 this.PaintTransparentBackground(pevent.Graphics, this.ClientRectangle); 105 } 106 } 107 108 /// <summary> 109 /// TabContorl 背景色設置 110 /// </summary> 111 /// <param name="g"></param> 112 /// <param name="clipRect"></param> 113 protected void PaintTransparentBackground(Graphics g, Rectangle clipRect) 114 { 115 if ((this.Parent != null)) 116 { 117 clipRect.Offset(this.Location); 118 PaintEventArgs e = new PaintEventArgs(g, clipRect); 119 GraphicsState state = g.Save(); 120 g.SmoothingMode = Smoot