// *********************************************************************** // Assembly : HZH_Controls // Created : 08-17-2019 // // *********************************************************************** // // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com // // // Blog: https://www.cnblogs.com/bfyx // GitHub:https://github.com/kwwwvagaa/NetWinformControl // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git // // If you use this code, please keep this note. // *********************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace HZH_Controls.Controls { /// /// Class TabControlExt. /// Implements the /// /// public class TabControlExt : TabControl { /// /// Initializes a new instance of the class. /// public TabControlExt() : base() { SetStyles(); //this.Multiline = true; this.ItemSize = new Size(this.ItemSize.Width, 50); } /// /// Sets the styles. /// private void SetStyles() { base.SetStyle( ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); base.UpdateStyles(); } /// /// Gets or sets a value indicating whether this instance is show close BTN. /// /// true if this instance is show close BTN; otherwise, false. [Description("是否显示关闭按钮"), Category("自定义")] public bool IsShowCloseBtn { get; set; } /// /// The back color /// private Color _backColor = Color.White; /// /// 此成员对于此控件无意义。 /// /// The color of the back. [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] [DefaultValue(typeof(Color), "White")] public override Color BackColor { get { return _backColor; } set { _backColor = value; base.Invalidate(true); } } /// /// The border color /// private Color _borderColor = Color.FromArgb(232, 232, 232); /// /// Gets or sets the color of the border. /// /// The color of the border. [DefaultValue(typeof(Color), "232, 232, 232")] [Description("TabContorl边框色")] public Color BorderColor { get { return _borderColor; } set { _borderColor = value; base.Invalidate(true); } } /// /// The head selected back color /// private Color _headSelectedBackColor = Color.FromArgb(255, 85, 51); /// /// Gets or sets the color of the head selected back. /// /// The color of the head selected back. [DefaultValue(typeof(Color), "255, 85, 51")] [Description("TabPage头部选中后的背景颜色")] public Color HeadSelectedBackColor { get { return _headSelectedBackColor; } set { _headSelectedBackColor = value; } } /// /// The head selected border color /// private Color _headSelectedBorderColor = Color.FromArgb(232, 232, 232); /// /// Gets or sets the color of the head selected border. /// /// The color of the head selected border. [DefaultValue(typeof(Color), "232, 232, 232")] [Description("TabPage头部选中后的边框颜色")] public Color HeadSelectedBorderColor { get { return _headSelectedBorderColor; } set { _headSelectedBorderColor = value; } } /// /// The header back color /// private Color _headerBackColor = Color.White; /// /// Gets or sets the color of the header back. /// /// The color of the header back. [DefaultValue(typeof(Color), "White")] [Description("TabPage头部默认背景颜色")] public Color HeaderBackColor { get { return _headerBackColor; } set { _headerBackColor = value; } } /// /// 绘制控件的背景。 /// /// 包含有关要绘制的控件的信息的 。 protected override void OnPaintBackground(PaintEventArgs pevent) { if (this.DesignMode == true) { LinearGradientBrush backBrush = new LinearGradientBrush( this.Bounds, SystemColors.ControlLightLight, SystemColors.ControlLight, LinearGradientMode.Vertical); pevent.Graphics.FillRectangle(backBrush, this.Bounds); backBrush.Dispose(); } else { this.PaintTransparentBackground(pevent.Graphics, this.ClientRectangle); } } /// /// TabContorl 背景色设置 /// /// The g. /// The clip rect. protected void PaintTransparentBackground(Graphics g, Rectangle clipRect) { if ((this.Parent != null)) { clipRect.Offset(this.Location); PaintEventArgs e = new PaintEventArgs(g, clipRect); GraphicsState state = g.Save(); g.SmoothingMode = SmoothingMode.HighSpeed; try { g.TranslateTransform((float)-this.Location.X, (float)-this.Location.Y); this.InvokePaintBackground(this.Parent, e); this.InvokePaint(this.Parent, e); } finally { g.Restore(state); clipRect.Offset(-this.Location.X, -this.Location.Y); //新加片段,待测试 using (SolidBrush brush = new SolidBrush(_backColor)) { clipRect.Inflate(1, 1); g.FillRectangle(brush, clipRect); } } } else { System.Drawing.Drawing2D.LinearGradientBrush backBrush = new System.Drawing.Drawing2D.LinearGradientBrush(this.Bounds, SystemColors.ControlLightLight, SystemColors.ControlLight, System.Drawing.Drawing2D.LinearGradientMode.Vertical); g.FillRectangle(backBrush, this.Bounds); backBrush.Dispose(); } } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnPaint(PaintEventArgs e) { // Paint the Background base.OnPaint(e); this.PaintTransparentBackground(e.Graphics, this.ClientRectangle); this.PaintAllTheTabs(e); this.PaintTheTabPageBorder(e); this.PaintTheSelectedTab(e); } /// /// Paints all the tabs. /// /// The instance containing the event data. private void PaintAllTheTabs(System.Windows.Forms.PaintEventArgs e) { if (this.TabCount > 0) { for (int index = 0; index < this.TabCount; index++) { this.PaintTab(e, index); } } } /// /// Paints the tab. /// /// The instance containing the event data. /// The index. private void PaintTab(System.Windows.Forms.PaintEventArgs e, int index) { GraphicsPath path = this.GetTabPath(index); this.PaintTabBackground(e.Graphics, index, path); this.PaintTabBorder(e.Graphics, index, path); this.PaintTabText(e.Graphics, index); this.PaintTabImage(e.Graphics, index); if (IsShowCloseBtn) { Rectangle rect = this.GetTabRect(index); e.Graphics.DrawLine(new Pen(_borderColor, 1F), new Point(rect.Right - 15, rect.Top + 5), new Point(rect.Right - 5, rect.Top + 15)); e.Graphics.DrawLine(new Pen(_borderColor, 1F), new Point(rect.Right - 5, rect.Top + 5), new Point(rect.Right - 15, rect.Top + 15)); } } /// /// 设置选项卡头部颜色 /// /// The graph. /// The index. /// The path. private void PaintTabBackground(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path) { Rectangle rect = this.GetTabRect(index); if (rect.Width == 0 || rect.Height == 0) return; System.Drawing.Brush buttonBrush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, _headerBackColor, _headerBackColor, LinearGradientMode.Vertical); //非选中时候的 TabPage 页头部背景色 graph.FillPath(buttonBrush, path); //if (index == this.SelectedIndex) //{ // //buttonBrush = new System.Drawing.SolidBrush(_headSelectedBackColor); // graph.DrawLine(new Pen(_headerBackColor), rect.Right+2, rect.Bottom, rect.Left + 1, rect.Bottom); //} buttonBrush.Dispose(); } /// /// 设置选项卡头部边框色 /// /// The graph. /// The index. /// The path. private void PaintTabBorder(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path) { Pen borderPen = new Pen(_borderColor);// TabPage 非选中时候的 TabPage 头部边框色 if (index == this.SelectedIndex) { borderPen = new Pen(_headSelectedBorderColor); // TabPage 选中后的 TabPage 头部边框色 } graph.DrawPath(borderPen, path); borderPen.Dispose(); } /// /// Paints the tab image. /// /// The g. /// The index. private void PaintTabImage(System.Drawing.Graphics g, int index) { Image tabImage = null; if (this.TabPages[index].ImageIndex > -1 && this.ImageList != null) { tabImage = this.ImageList.Images[this.TabPages[index].ImageIndex]; } else if (this.TabPages[index].ImageKey.Trim().Length > 0 && this.ImageList != null) { tabImage = this.ImageList.Images[this.TabPages[index].ImageKey]; } if (tabImage != null) { Rectangle rect = this.GetTabRect(index); g.DrawImage(tabImage, rect.Right - rect.Height - 4, 4, rect.Height - 2, rect.Height - 2); } } /// /// Paints the tab text. /// /// The graph. /// The index. private void PaintTabText(System.Drawing.Graphics graph, int index) { string tabtext = this.TabPages[index].Text; System.Drawing.StringFormat format = new System.Drawing.StringFormat(); format.Alignment = StringAlignment.Near; format.LineAlignment = StringAlignment.Center; format.Trimming = StringTrimming.EllipsisCharacter; Brush forebrush = null; if (this.TabPages[index].Enabled == false) { forebrush = SystemBrushes.ControlDark; } else { forebrush = SystemBrushes.ControlText; } Font tabFont = this.Font; if (index == this.SelectedIndex) { if (this.TabPages[index].Enabled != false) { forebrush = new SolidBrush(_headSelectedBackColor); } } Rectangle rect = this.GetTabRect(index); var txtSize = ControlHelper.GetStringWidth(tabtext, graph, tabFont); Rectangle rect2 = new Rectangle(rect.Left + (rect.Width - txtSize) / 2 - 1, rect.Top, rect.Width, rect.Height); graph.DrawString(tabtext, tabFont, forebrush, rect2, format); } /// /// 设置 TabPage 内容页边框色 /// /// The instance containing the event data. private void PaintTheTabPageBorder(System.Windows.Forms.PaintEventArgs e) { if (this.TabCount > 0) { Rectangle borderRect = this.TabPages[0].Bounds; //borderRect.Inflate(1, 1); Rectangle rect = new Rectangle(borderRect.X - 2, borderRect.Y - 1, borderRect.Width + 5, borderRect.Height + 2); ControlPaint.DrawBorder(e.Graphics, rect, this.BorderColor, ButtonBorderStyle.Solid); } } /// /// Paints the selected tab. /// /// The instance containing the event data. private void PaintTheSelectedTab(System.Windows.Forms.PaintEventArgs e) { if (this.SelectedIndex == -1) return; Rectangle selrect; int selrectRight = 0; selrect = this.GetTabRect(this.SelectedIndex); selrectRight = selrect.Right; e.Graphics.DrawLine(new Pen(_headSelectedBackColor), selrect.Left, selrect.Bottom + 1, selrectRight, selrect.Bottom + 1); } /// /// Gets the tab path. /// /// The index. /// GraphicsPath. private GraphicsPath GetTabPath(int index) { System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath(); path.Reset(); Rectangle rect = this.GetTabRect(index); switch (Alignment) { case TabAlignment.Top: break; case TabAlignment.Bottom: break; case TabAlignment.Left: break; case TabAlignment.Right: break; } path.AddLine(rect.Left, rect.Top, rect.Left, rect.Bottom + 1); path.AddLine(rect.Left, rect.Top, rect.Right, rect.Top); path.AddLine(rect.Right, rect.Top, rect.Right, rect.Bottom + 1); path.AddLine(rect.Right, rect.Bottom + 1, rect.Left, rect.Bottom + 1); return path; } /// /// Sends the message. /// /// The h WND. /// The MSG. /// The w parameter. /// The l parameter. /// IntPtr. [DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); /// /// The wm setfont /// private const int WM_SETFONT = 0x30; /// /// The wm fontchange /// private const int WM_FONTCHANGE = 0x1d; /// /// 引发 方法。 /// protected override void OnCreateControl() { base.OnCreateControl(); this.OnFontChanged(EventArgs.Empty); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); IntPtr hFont = this.Font.ToHfont(); SendMessage(this.Handle, WM_SETFONT, hFont, (IntPtr)(-1)); SendMessage(this.Handle, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero); this.UpdateStyles(); } /// /// 此成员重写 。 /// /// 一个 Windows 消息对象。 protected override void WndProc(ref Message m) { if (m.Msg == 0x0201) // WM_LBUTTONDOWN { if (!DesignMode) { if (IsShowCloseBtn) { var mouseLocation = this.PointToClient(Control.MousePosition); int index = GetMouseDownTabHead(mouseLocation); if (index >= 0) { Rectangle rect = this.GetTabRect(index); var closeRect = new Rectangle(rect.Right - 15, rect.Top + 5, 10, 10); if (closeRect.Contains(mouseLocation)) { this.TabPages.RemoveAt(index); return; } } } } } base.WndProc(ref m); } /// /// 在调度键盘或输入消息之前,在消息循环内对它们进行预处理。 /// /// 通过引用传递的 ,它表示要处理的消息。可能的值有 WM_KEYDOWN、WM_SYSKEYDOWN、WM_CHAR 和 WM_SYSCHAR。 /// 如果消息已由控件处理,则为 true;否则为 false。 /// /// /// /// /// /// public override bool PreProcessMessage(ref Message msg) { return base.PreProcessMessage(ref msg); } /// /// Gets the mouse down tab head. /// /// The point. /// System.Int32. private int GetMouseDownTabHead(Point point) { for (int i = 0; i < this.TabCount; i++) { Rectangle rect = this.GetTabRect(i); if (rect.Contains(point)) { return i; } } return -1; } } }