TabControl с кнопкой закрыть и добавить

Я пытаюсь сделать элемент управления вкладкой " x "(кнопка закрытия) и " + " (кнопка новой вкладки). Я нашел решение добавить x button вкладка выглядит так:

enter image description here

но я хочу добавить + где этот черный круг прямо сейчас. Я понятия не имею, как, я попробовал рисовать на 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 ответов


как вариант можно добавить дополнительную вкладку, которая показывает значок Add и проверьте, когда пользователь нажимает на эту вкладку, а затем вставьте новый TabPage перед ним.

также вы можете предотвратить выбор этой дополнительной вкладки, просто используя Selecting событие TabControl. Таким образом, последняя вкладка действует только как кнопка добавления для вас, например IE и Chrome.

Tab with close and add button

Детали Реализации

мы будем использовать вкладку рисования владельца, чтобы показать закрыть значки на каждой вкладке значок добавления на последней вкладке. Мы используем 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 Add и вблизи Close кнопки.

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]);
    }
}

вы можете попробовать изменить его немного, пока он соответствует вашим потребностям.