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, чтобы отвести его от последней вкладки. Как это исправить?. Я сам не рисовал на заказ, я учусь этому.
3 ответов
как вариант можно добавить дополнительную вкладку, которая показывает значок и проверьте, когда пользователь нажимает на эту вкладку, а затем вставьте новый TabPage
перед ним.
также вы можете предотвратить выбор этой дополнительной вкладки, просто используя Selecting
событие TabControl
. Таким образом, последняя вкладка действует только как кнопка добавления для вас, например IE и Chrome.
Детали Реализации
мы будем использовать вкладку рисования владельца, чтобы показать закрыть значки на каждой вкладке значок добавления на последней вкладке. Мы используем DrawItem
чтобы приблизиться и добавить иконки, MouseDown
для обработки нажмите кнопку Закрыть и добавить кнопки, Selecting
чтобы предотвратить выбор последней вкладки и HandleCreated
для регулировки ширины вкладки. Вы можете увидеть все настройки и коды реализации ниже.
инициализации
установить заполнение и DrawMode
и назначить обработчики событий для DrawItem
, MouseDown
, Selecting
и HandleCreated
событие.
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;
ручка нажмите на кнопку "Закрыть" и добавить кнопку
вы можете справиться MouseDown
или MouseClick
событие и проверьте, содержит ли прямоугольник последней вкладки точку щелчка мыши, затем вставьте вкладку перед последней вкладкой. Проверить Otherwose если один из следующих кнопок нажал местоположение, а затем закрыть вкладку, в которой его закрыть кнопка была нажата:
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;
}
}
}
}
предотвратить выбор последней вкладки
для предотвращения отбора последняя вкладка, вы можете обрабатывать Selecting
событие управления и проверьте, является ли вкладка выбора последней вкладкой, отмените событие:
private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
{
if (e.TabPageIndex == this.tabControl1.TabCount - 1)
e.Cancel = true;
}
нарисуйте кнопку закрытия и добавьте кнопку
чтобы нарисовать кнопку закрытия и добавить кнопку, Вы можете обрабатывать DrawItem
событие. Я использовал эти значки для add и вблизи кнопки.
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);
}
}
регулировка ширины вкладки
чтобы настроить ширину вкладки и позволить последней вкладке иметь меньшую ширину, вы можете hanlde 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);
}
скачать
вы можете скачать код или клонировать репозиторий здесь:
обычно прямой, "низкоуровневый" способ сделать что-то вроде этого-это обработать Paint
событие и рисуют в TabControl
себя, а затем также обрабатывать события ввода мыши для обнаружения кликов, где вы нарисовали.
однако, а) это боль, и Б)TabControl
запрещает Paint
событие, поэтому невозможно справиться, не перейдя даже на более низкий уровень и не имея дело с WM_PAINT
сообщении WndProc()
метод переопределить.
для ваших целей, я рекомендую просто добавить новый элемент, например Button
до Form
, помещая его как раз над местом на TabControl
где вы хотите, чтобы пользователь мог нажать. Тогда в Button.Click
обработчик событий, вы можете добавить новую страницу по желанию. Если вы хотите инкапсулировать комбинацию Button
и TabControl
, вы можете использовать UserControl
.
для пример:
TabControlWithAdd.Дизайнер.cs:
partial class TabControlWithAdd
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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, r.X +10 + MoveRight - 2, r.Y, r.X +10 + MoveRight + r.Width, r.Y + r.Height+2);
e.Graphics.DrawLine(p, r.X +10 + MoveRight + r.Width, r.Y, r.X + 10 + MoveRight-2, r.Y + r.Height+2);
e.Graphics.DrawString(boldLetter, f1, b1, new PointF(r.X, r.Y));
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(r.X + 5, r.Y));
}
}
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;
r.X = r.X + 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]);
}
}
вы можете попробовать изменить его немного, пока он соответствует вашим потребностям.