2016-04-27 3 views
7

Я пытаюсь сделать элемент управления вкладкой «x» (кнопка закрытия) и «+» (новая кнопка вкладок). Я нашел решение, чтобы добавить x button, вкладка будет выглядеть так:TabControl with Close и Add 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, чтобы отвести его от последней вкладки. Как это исправить? Я сам не нарисовал собственный рисунок, я его изучаю.

+0

См. [TabControl и границы визуального сбоя] (http://stackoverflow.com/a/7785745/719186) – LarsTech

+0

Я не уверен, как это связано с моим вопросом? Он попытался удалить пространство, на котором я хочу рисовать? – Jack

+0

Вы пытаетесь рисовать область управления вкладками, а не в области страницы. Попробуйте адаптировать его к вашим потребностям. Может показаться мерцающим с тех пор, как TabControl делает стиль старой школы win32. – LarsTech

ответ

9

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

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

Tab with close and add button

Подробности реализации

Мы будем использовать владельца сделать вкладку, чтобы показать близкие значки на каждой вкладке значок добавления на последней вкладке.Мы используем DrawItem, чтобы нарисовать близко и добавить значки, MouseDown, чтобы обработать щелчок по закрытию и добавить кнопки, Selecting, чтобы предотвратить выбор последней вкладки и HandleCreated для настройки ширины вкладки. Вы можете увидеть все параметры и коды реализации ниже.

Initialization

Набор набивка и 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 и закройте кнопки 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); 
    } 
} 

Adjust Tab Ширина

Для регулировки ширины вкладок и пусть последняя вкладка имеет меньшую ширину, вы можете 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); 
} 
+0

@Jack, я догадался, может быть, вас не интересует логика рисования закрытой значки, плюс значок и закрывающие вкладки.Поэтому, чтобы сохранить ответ более чистым, я поделился только логикой предотвращения выбора последней вкладки и проверки щелчка на последней вкладке. дайте мне знать, если у вас есть вопрос об ответе :) –

+0

Я пытаюсь использовать этот подход. Я нашел ошибку в приложении, когда у вас есть только одна вкладка, а также «новая вкладка», когда вы нажмете кнопку «x», мышь автоматически переместится на вкладку «новая вкладка» и создаст новую, таким образом, я никогда не удаляйте все вкладки, если я не нажму кнопку x и не нажмем кнопку мыши, перетащите курсор от «новой вкладки». Я думаю, что проблема заключается в проверке 'this.tabControl1.GetTabRect (lastIndex) .Contains (e.Location)', которая соответствует всем вкладкам, а не только кнопке «+» (я использую SizeMode = Исправлено, поэтому вкладка больше, чем значок «+»). Я не собирался исправлять любую идею? – Jack

+0

@ Джэк, я сейчас на мобильном телефоне, я проверю его завтра и поделится с вами результатом. Но я думаю, что у меня не было такой проблемы. Если вы нажмете кнопку мыши, нажмите кнопку в любом месте последней вкладки, а затем выполните добавление и возврат. В противном случае нажмите кнопку закрытия. Это должно сработать. –

0

Обычно, «низкоуровневый» способ сделать что-то подобное, должен обрабатывать событие Paint и рисовать его непосредственно в TabControl, а затем также обрабатывать события ввода мыши для обнаружения кликов, на которых вы нарисовали.

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

0

Другой способ идти о его создании нового 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]); 
    } 
} 

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