Подтвердить что ты не робот

TabControl с кнопкой Close и Add

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

4b9b3361

Ответ 1

В качестве опции вы можете добавить дополнительную вкладку со значком добавления 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 и проверить, содержит ли прямоangularьник последней вкладки точку щелчка мыши, затем вставить вкладку перед последней вкладкой. В противном случае проверьте, содержит ли одна из кнопок закрытия нажатое местоположение, затем закройте вкладку, на которой была нажата кнопка закрытия:

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 и закрытия кнопок 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);
    }
}

Отрегулируйте ширину вкладки

Чтобы настроить ширину вкладки и позволить последней вкладке иметь меньшую ширину, вы можете передать событие 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);
}

Скачать

Вы можете скачать код или клонировать репозиторий здесь:

Ответ 2

Как правило, прямой, "низкоуровневый" способ сделать что-то вроде этого, должен обрабатывать событие Paint и рисовать в самом TabControl, а затем также обрабатывать события ввода мыши для обнаружения кликов, где у вас есть обращается.

Тем не менее, a) что боль и b) TabControl подавляет событие Paint, поэтому его невозможно обрабатывать, не переходя еще на нижний уровень и не имея дело с сообщением WM_PAINT в WndProc() метод переопределения.

В ваших целях я бы рекомендовал просто добавить новый элемент управления, например. a Button, в Form, разместив его как раз над местом на TabControl, где вы хотите, чтобы пользователь мог щелкнуть. Затем в обработчике событий Button.Click вы можете добавить новую страницу по своему желанию. Если вы хотите инкапсулировать комбинацию Button и TabControl, вы можете использовать UserControl.

Например:

TabControlWithAdd.Designer.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 (например, если вы не хотите внешний вид кнопки), чтобы создать необходимый визуальный эффект.

Ответ 3

Еще один способ сделать это - создать новый 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]);
    }
}

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