带关闭和添加按钮的TabControl

我想让一个标签控件有一个“x”(关闭按钮)和“+”(新标签按钮)。 我找到了一个添加x button的解决方案,该选项卡现在看起来像这样:

在此处输入图像描述

但是我想现在添加一个+那个黑圈。 我不知道如何,我尝试绘制最后一个标签的Paint事件,如下所示:

 var p = tabs.TabPages[tabs.TabCount - 1]; p.Paint += new PaintEventHandler(tab_OnDrawPage); private void tab_OnDrawPage(object sender, PaintEventArgs e) { // e.ClipRectangle. e.Graphics.DrawString("+", new Font("verdana", 10, FontStyle.Bold), Brushes.Black, e.ClipRectangle.X + 10, e.ClipRectangle.Y + 10); } 

但它并没有显示任何吸引力。 我想这与我传递给DrawString()调用的位置有关,但我不知道要使用的正确位置。 我使用+10将它从最后一个标签中拉出来。 如何解决? 我自己没有做过任何自定义绘图,我正在学习它。

作为选项,您可以添加一个显示添加图标的额外选项卡 加 并检查用户何时单击该选项卡,然后在其前面插入新的TabPage

此外,您可以使用Selecting TabControl事件来阻止选择该额外选项卡。 这样,最后一个标签就像是一个添加按钮,就像IE和Chrome一样。

选项卡与关闭和添加按钮

实施细节

我们将使用所有者绘制选项卡在每个选项卡上显示最后一个选项卡上的添加图标。 我们使用DrawItem绘制关闭并添加图标,使用MouseDown处理单击关闭并添加按钮, Selecting以防止选择最后一个选项卡,使用HandleCreated调整选项卡宽度。 您可以在下面看到所有实施设置和代码。

初始化

设置padding和DrawMode并为DrawItemMouseDownSelectingHandleCreated事件分配事件处理程序。

 this.tabControl1.Padding = new Point(12, 4); this.tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed; this.tabControl1.DrawItem += tabControl1_DrawItem; this.tabControl1.MouseDown += tabControl1_MouseDown; this.tabControl1.Selecting += tabControl1_Selecting; this.tabControl1.HandleCreated += tabControl1_HandleCreated; 

处理单击关闭按钮并添加按钮

您可以处理MouseDownMouseClick事件,并检查最后一个选项卡矩形是否包含鼠标单击的点,然后在最后一个选项卡之前插入选项卡。 其他函数检查其中一个关闭按钮是否包含单击的位置,然后关闭其单击其关闭按钮的选项卡:

 private void tabControl1_MouseDown(object sender, MouseEventArgs e) { var lastIndex = this.tabControl1.TabCount - 1; if (this.tabControl1.GetTabRect(lastIndex).Contains(e.Location)) { this.tabControl1.TabPages.Insert(lastIndex, "New Tab"); this.tabControl1.SelectedIndex = lastIndex; } else { for (var i = 0; i < this.tabControl1.TabPages.Count; i++) { var tabRect = this.tabControl1.GetTabRect(i); tabRect.Inflate(-2, -2); var closeImage = Properties.Resources.DeleteButton_Image; var imageRect = new Rectangle( (tabRect.Right - closeImage.Width), tabRect.Top + (tabRect.Height - closeImage.Height) / 2, closeImage.Width, closeImage.Height); if (imageRect.Contains(e.Location)) { this.tabControl1.TabPages.RemoveAt(i); break; } } } } 

防止selectin最后一个标签

要防止选择最后一个选项卡,您可以处理Selecting控件事件并检查选择选项卡是否为最后一个选项卡,取消该事件:

 private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e) { if (e.TabPageIndex == this.tabControl1.TabCount - 1) e.Cancel = true; } 

绘制关闭按钮和添加按钮

要绘制关闭按钮并添加按钮,您可以处理DrawItem事件。 我用这些图标添加 加 并关闭 关 纽扣。

 private void tabControl1_DrawItem(object sender, DrawItemEventArgs e) { var tabPage = this.tabControl1.TabPages[e.Index]; var tabRect = this.tabControl1.GetTabRect(e.Index); tabRect.Inflate(-2, -2); if (e.Index == this.tabControl1.TabCount - 1) { var addImage = Properties.Resources.AddButton_Image; e.Graphics.DrawImage(addImage, tabRect.Left + (tabRect.Width - addImage.Width) / 2, tabRect.Top + (tabRect.Height - addImage.Height) / 2); } else { var closeImage = Properties.Resources.DeleteButton_Image; e.Graphics.DrawImage(closeImage, (tabRect.Right - closeImage.Width), tabRect.Top + (tabRect.Height - closeImage.Height) / 2); TextRenderer.DrawText(e.Graphics, tabPage.Text, tabPage.Font, tabRect, tabPage.ForeColor, TextFormatFlags.Left); } } 

调整标签宽度

要调整选项卡宽度并让最后一个选项卡具有较小的宽度,您可以处理HandleCreated事件并将TCM_SETMINTABWIDTH发送到控件并指定选项卡宽度允许的最小大小:

 [DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); private const int TCM_SETMINTABWIDTH = 0x1300 + 49; private void tabControl1_HandleCreated(object sender, EventArgs e) { SendMessage(this.tabControl1.Handle, TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)16); } 

下载

您可以在此处下载代码或克隆存储库:

  • R-aghaei / TabControlWithCloseButtonAndAddButton

通常,执行此类操作的直接“低级”方法是处理Paint事件并绘制到TabControl本身,然后还处理鼠标输入事件以检测您绘制的点击。

然而,a)这是一个痛苦,并且b) TabControl抑制了Paint事件,因此在WndProc()方法覆盖中不进行更低级别处理WM_PAINT消息就不可能处理。

为了您的目的,我建议您只需将新控件(例如Button )添加到Form ,将其放在TabControl上您希望用户可以单击的位置上。 然后在Button.Click事件处理程序中,您可以根据需要添加新页面。 如果要封装ButtonTabControl的组合,可以使用UserControl

例如:

TabControlWithAdd.Designer.cs:

 partial class TabControlWithAdd { ///  /// Required designer variable. ///  private System.ComponentModel.IContainer components = null; ///  /// Clean up any resources being used. ///  /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code ///  /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///  private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.tabControl1.SuspendLayout(); this.SuspendLayout(); // // button1 // this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.button1.Location = new System.Drawing.Point(247, 3); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(23, 23); this.button1.TabIndex = 0; this.button1.Text = "+"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // tabControl1 // this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Controls.Add(this.tabPage2); this.tabControl1.Location = new System.Drawing.Point(3, 3); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; this.tabControl1.Size = new System.Drawing.Size(267, 181); this.tabControl1.TabIndex = 1; // // tabPage1 // this.tabPage1.Location = new System.Drawing.Point(4, 25); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); this.tabPage1.Size = new System.Drawing.Size(259, 152); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "tabPage1"; this.tabPage1.UseVisualStyleBackColor = true; // // tabPage2 // this.tabPage2.Location = new System.Drawing.Point(4, 25); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); this.tabPage2.Size = new System.Drawing.Size(192, 71); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "tabPage2"; this.tabPage2.UseVisualStyleBackColor = true; // // TabControlWithAdd // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.button1); this.Controls.Add(this.tabControl1); this.Name = "TabControlWithAdd"; this.Size = new System.Drawing.Size(273, 187); this.tabControl1.ResumeLayout(false); this.ResumeLayout(false); } #endregion private System.Windows.Forms.Button button1; private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; } 

TabControlWithAdd.cs:

 public partial class TabControlWithAdd : UserControl { public TabControlWithAdd() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { tabControl1.TabPages.Add("Tab " + (tabControl1.TabPages.Count + 1)); } } 

以上使用Button ,但当然您可以使用任何其他您喜欢的可点击控件,包括Label (例如,如果您不想要按钮边框外观),以产生您想要的视觉效果。

另一种方法是创建一个新的TabControl ,它扩展了TabControl类。 我曾经遇到过同样的问题,这就是我的做法,我找不到完成的代码,但这可以在你的标签上添加一个X ,同样可以用于+符号:

 public delegate bool PreRemoveTab(int indx); public class TabControlEx : TabControl { public TabControlEx() : base() { PreRemoveTabPage = null; this.DrawMode = TabDrawMode.OwnerDrawFixed; } public PreRemoveTab PreRemoveTabPage; protected const int size = 5; protected int moveRight = 0; protected int MoveRight { get { return moveRight; } set { moveRight = value; } } protected override void OnDrawItem(DrawItemEventArgs e) { Brush b = new SolidBrush(Color.Salmon); Brush b1 = new SolidBrush(Color.Black); Font f = this.Font; Font f1 = new Font("Arial", 9,FontStyle.Bold); if (e.Index != 0) { Rectangle r = e.Bounds; r = GetTabRect(e.Index); r.Offset(2, 2); r.Width = size; r.Height = size; Pen p = new Pen(b,2); string title = this.TabPages[e.Index].Text; string boldLetter = title.Substring(0, 1); title = title.Remove(0, 1); MoveRight = ((Int32)e.Graphics.MeasureString(title, f, 200).Width) + 1; // -1 e.Graphics.DrawLine(p, rX +10 + MoveRight - 2, rY, rX +10 + MoveRight + r.Width, rY + r.Height+2); e.Graphics.DrawLine(p, rX +10 + MoveRight + r.Width, rY, rX + 10 + MoveRight-2, rY + r.Height+2); e.Graphics.DrawString(boldLetter, f1, b1, new PointF(rX, rY)); e.Graphics.DrawString(title, f, b1, new PointF(r.X+8, r.Y+1)); } else { Rectangle r = GetTabRect(e.Index); e.Graphics.DrawString(this.TabPages[e.Index].Text, f, b1, new PointF(rX + 5, rY)); } } protected override void OnMouseClick(MouseEventArgs e) { Point p = e.Location; for (int i = 0; i < TabCount; i++) { Rectangle r = GetTabRect(i); r.Offset(2, 2); r.Width = size+2; r.Height = size+2; rX = rX + MoveRight + 8; if (r.Contains(p)) { if (i != 0) { CloseTab(i); } } } } private void CloseTab(int i) { if (PreRemoveTabPage != null) { bool closeIt = PreRemoveTabPage(i); if (!closeIt) return; } TabPages.Remove(TabPages[i]); } } 

您可以尝试稍微修改它,直到它符合您的需要。