Results 1 to 3 of 3

Thread: TabControl with Close Button and Text Align

  1. #1

    Thread Starter
    Member
    Join Date
    Mar 2011
    Posts
    39

    TabControl with Close Button and Text Align

    One major flaw in the Tab Control in VB is the fact that it doesn't have a close button. Another issue is the alignment of the text. Usually these two problems can't be solved without manually drawing them on and changing the DrawMode to OwnerDrawFixed. And even once you do that, the tabs usually end up looking terrible.

    Here's a way that I found to get a close button on tabs and also align the text however you want!

    This is a more advanced version of the following code. I added the text fix and fixed a few minor issues with what he already had:
    http://www.vbforums.com/showthread.php?t=622242

    How to use:
    1. Add a new class to your application (preferably named TabControlEx.vb)
    2. Copy and paste this code into that class.
    3. Add the attached image to resources. You can use your own, but I really like the way this one looks.
    3. Rebuild.
    4. Now you should see a new item in the Control Toolbox named TabControlEx. Drag this control to your form.

    New Features:
    1. The ShowCloseButtonOnTabs property controls whether close button is shown on the tabs on not. By default this is True.
    2. The CloseButtonClick event is raised when any of the close buttons is clicked. By default this closes the tab, but you can set the e.Cancel = True inside this event handler to prevent closing the tab.
    3. Text on tabs is aligned the way you want it. Changed the text/font the way you normally would (TabControl.text = w/e) and it will automatically appear properly.

    Note:
    -The width of the tab I tested it with was 115
    -Change occurrences of the following to change the way the text is aligned:
    TabName.Size = New Size(rect.Width - btn.Width - 10, rect.Height)
    TabName.Location = New Point(rect.X + 10, rect.Y + 1)

    **** The 'X' Does Not Show Up On the First Tab When It's The Only One Open!****
    **** I did this on purpose****
    You can fix this very easily by taking out the if statement that sets it's visibility to false
    in the functioncalled RePositionCloseButtons. But you will need to add another if
    statement in the function OnCloseButtonClick that will close the form if the TabCount -1
    is 0. This is to prevent crashing. I just thought it was a neat feature to not show the 'X'.
    It's the same way in FireFox.
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by Zombie666; May 20th, 2011 at 01:02 AM.

  2. #2

    Thread Starter
    Member
    Join Date
    Mar 2011
    Posts
    39

    Re: TabControl with Close Button and Text Align

    Here's the first part of the code:

    VB .NET Code:
    1. Option Strict On
    2. Imports System.ComponentModel
    3.  
    4. <ToolboxBitmap(GetType(System.Windows.Forms.TabControl))> _
    5. Public Class TabControlEx
    6.     Inherits TabControl
    7.  
    8.     Private Declare Auto Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    9.     Protected CloseButtonCollection As New Dictionary(Of Button, TabPage)
    10.     Private _ShowCloseButtonOnTabs As Boolean = True
    11.     Protected LabelCollection As New Dictionary(Of Label, TabPage)
    12.  
    13.     <Browsable(True), DefaultValue(True), Category("Behavior"), Description("Indicates whether a close button should be shown on each TabPage")> _
    14.     Public Property ShowCloseButtonOnTabs() As Boolean
    15.         Get
    16.             Return _ShowCloseButtonOnTabs
    17.         End Get
    18.         Set(ByVal value As Boolean)
    19.             _ShowCloseButtonOnTabs = value
    20.             For Each btn In CloseButtonCollection.Keys
    21.                 btn.Visible = _ShowCloseButtonOnTabs
    22.             Next
    23.             RePositionCloseButtons()
    24.         End Set
    25.     End Property
    26.  
    27.     Protected Overrides Sub OnCreateControl()
    28.         MyBase.OnCreateControl()
    29.         RePositionCloseButtons()
    30.     End Sub
    31.  
    32.     Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
    33.         MyBase.OnControlAdded(e)
    34.         Dim tp As TabPage = DirectCast(e.Control, TabPage)
    35.         Dim rect As Rectangle = Me.GetTabRect(Me.TabPages.IndexOf(tp))
    36.         Dim btn As Button = AddCloseButton(tp)
    37.  
    38.         AddHandler btn.MouseEnter, AddressOf OnBtnMouseEnter
    39.         AddHandler btn.MouseLeave, AddressOf OnBtnMouseLeave
    40.         AddHandler btn.MouseDown, AddressOf onBtnMouseDown
    41.  
    42.         btn.Size = New Size(rect.Height - 1, rect.Height - 1)
    43.         btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
    44.         SetParent(btn.Handle, Me.Handle)
    45.         AddHandler btn.Click, AddressOf OnCloseButtonClick
    46.         CloseButtonCollection.Add(btn, tp)
    47.  
    48.         Dim TabName As Label = AddLabel(tp)
    49.         TabName.Size = New Size(rect.Width - btn.Width - 10, rect.Height)
    50.         TabName.Location = New Point(rect.X + 10, rect.Y + 1)
    51.         SetParent(TabName.Handle, Me.Handle)
    52.         AddHandler TabName.MouseDown, AddressOf onLabelMouseDown
    53.         LabelCollection.Add(TabName, tp)
    54.  
    55.     End Sub
    56.  
    57.     Protected Overrides Sub OnControlRemoved(ByVal e As System.Windows.Forms.ControlEventArgs)
    58.         Dim btn As Button = CloseButtonOfTabPage(DirectCast(e.Control, TabPage))
    59.         RemoveHandler btn.Click, AddressOf OnCloseButtonClick
    60.         CloseButtonCollection.Remove(btn)
    61.         SetParent(btn.Handle, Nothing)
    62.         btn.Dispose()
    63.         MyBase.OnControlRemoved(e)
    64.  
    65.         Dim lbl As Label = LabelOfTabPage(DirectCast(e.Control, TabPage))
    66.         SetParent(lbl.handle, Nothing)
    67.         lbl.Dispose()
    68.         MyBase.OnControlRemoved(e)
    69.     End Sub
    70.  
    71.     Protected Overrides Sub OnLayout(ByVal levent As System.Windows.Forms.LayoutEventArgs)
    72.         MyBase.OnLayout(levent)
    73.         RePositionCloseButtons()
    74.     End Sub
    75.  
    76.     Protected Overridable Sub onLabelMouseDown(ByVal sender As Object, ByVal e As EventArgs)
    77.         If Me.TabCount > 1 Then
    78.             Dim TabName As Label = DirectCast(sender, Label)
    79.             Dim x As Integer = TabName.Location.X
    80.              'you can also enter the tab width in manually, mine was 115
    81.             x = x \ Me.ItemSize.Width
    82.             Me.SelectedTab = Me.TabPages(x)
    83.         End If
    84.     End Sub
    85.  
    86.     Public Event CloseButtonClick As CancelEventHandler
    87.     Protected Overridable Sub OnCloseButtonClick(ByVal sender As Object, ByVal e As EventArgs)
    88.  
    89.         If Me.TabCount > 1 Then
    90.             If Not DesignMode Then
    91.                 Dim btn As Button = DirectCast(sender, Button)
    92.                 Dim tp As TabPage = CloseButtonCollection(btn)
    93.  
    94.  
    95.                 Dim lastTab As Integer
    96.                 Dim closeIndex As Integer = btn.Location.X \ Me.ItemSize.Width
    97.                 If closeIndex >= Me.SelectedIndex And Me.SelectedIndex <> Me.TabCount - 1 Then
    98.                     lastTab = Me.SelectedIndex
    99.                 ElseIf closeIndex < Me.SelectedIndex Then
    100.                     lastTab = Me.SelectedIndex - 1
    101.                 ElseIf closeIndex = Me.SelectedIndex And Me.SelectedIndex <> 0 And Me.SelectedIndex <> Me.TabCount - 1 Then
    102.                     lastTab = Me.SelectedIndex + 1
    103.                 ElseIf closeIndex = Me.SelectedIndex AndAlso Me.SelectedIndex = Me.TabCount - 1 Then
    104.                     lastTab = Me.SelectedIndex - 1
    105.                 End If
    106.  
    107.                 Dim ee As New CancelEventArgs
    108.                 RaiseEvent CloseButtonClick(sender, ee)
    109.                 If Not ee.Cancel Then
    110.                     Me.TabPages.Remove(tp)
    111.                     RePositionCloseButtons()
    112.                 End If
    113.                 Me.SelectedIndex = lastTab
    114.             End If
    115.         End If
    116.     End Sub
    117.  
    118.     Protected Overridable Function AddLabel(ByVal tp As TabPage) As Label
    119.         Dim tablabel As New Label
    120.         With tablabel
    121.             .BackColor = Color.Transparent
    122.             .Font = Me.Font
    123.             .Text = tp.Text
    124.         End With
    125.         Return tablabel
    126.     End Function
    127.  
    128.     Protected Overridable Function AddCloseButton(ByVal tp As TabPage) As Button
    129.         Dim closeButton As New Button
    130.  
    131.         With closeButton
    132.             .FlatStyle = FlatStyle.Flat
    133.             .Text = "X"
    134.             .BackColor = Color.Transparent
    135.             .FlatAppearance.BorderSize = 0
    136.             .ForeColor = Color.Black
    137.             .Font = New Font("Microsoft Sans Serif", 6, FontStyle.Bold)
    138.         End With
    139.         Return closeButton
    140.     End Function
    141.  
    142.     Public Sub RePositionCloseButtons()
    143.         For Each item In CloseButtonCollection
    144.             RePositionCloseButtons(item.Value)
    145.         Next
    146.         For Each item In LabelCollection
    147.             RePositionCloseButtons(item.Value)
    148.         Next
    149.     End Sub
    150.  
    151.     Public Sub RePositionCloseButtons(ByVal tp As TabPage)
    152.         Dim btn As Button = CloseButtonOfTabPage(tp)
    153.         If btn IsNot Nothing Then
    154.             Dim tpIndex As Integer = Me.TabPages.IndexOf(tp)
    155.             If tpIndex >= 0 Then
    156.                 Dim rect As Rectangle = Me.GetTabRect(tpIndex)
    157.                 If Me.SelectedTab Is tp Then
    158.                     btn.Size = New Size(rect.Height - 1, rect.Height - 1)
    159.                     btn.Location = New Point(rect.X + rect.Width - rect.Height, rect.Y + 1)
    160.                 Else
    161.                     btn.BackgroundImage = My.Resources.btnBack
    162.                     btn.BackgroundImageLayout = ImageLayout.Stretch
    163.                     btn.Size = New Size(rect.Height - 2, rect.Height - 2)
    164.                     btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
    165.                 End If
    166.  
    167.                 Dim TabName As Label = LabelOfTabPage(tp)
    168.                 If TabName IsNot Nothing Then
    169.                     If tpIndex >= 0 Then
    170.                         If Me.SelectedTab Is tp Then
    171.                             TabName.Size = New Size(rect.Width - btn.Width - 10, rect.Height)
    172.                             TabName.Location = New Point(rect.X + 10, rect.Y + 1)
    173.                         Else
    174.                             TabName.BackgroundImage = My.Resources.btnBack
    175.                             TabName.BackgroundImageLayout = ImageLayout.Stretch
    176.                             TabName.Size = New Size(rect.Width - btn.Width - 13, rect.Height - 1)
    177.                             TabName.Location = New Point(rect.X + 10, rect.Y + 1)
    178.                         End If
    179.                     End If
    180.                     TabName.Text = tp.Text
    181.                     TabName.BringToFront()
    182.                 End If
    183.  
    184.                 If Me.TabCount > 1 Then
    185.                     btn.Visible = ShowCloseButtonOnTabs
    186.                 Else
    187.                     btn.Visible = False
    188.                     TabName.Size = New Size(rect.Width - 10, rect.Height)
    189.                 End If
    190.  
    191.                 btn.BringToFront()
    192.  
    193.             End If
    194.         End If
    195.     End Sub
    196.  
    197.     Protected Function CloseButtonOfTabPage(ByVal tp As TabPage) As Button
    198.         Return (From item In CloseButtonCollection Where item.Value Is tp Select item.Key).FirstOrDefault
    199.     End Function

    The rest is below!!!

    There were too many characters so I had to split it up.
    Last edited by Zombie666; May 19th, 2011 at 07:32 PM.

  3. #3

    Thread Starter
    Member
    Join Date
    Mar 2011
    Posts
    39

    Re: TabControl with Close Button and Text Align

    VB .NET Code:
    1. Protected Function LabelOfTabPage(ByVal tp As TabPage) As Label
    2.         Return (From item In LabelCollection Where item.Value Is tp Select item.Key).FirstOrDefault
    3.     End Function
    4.  
    5.  
    6.     Private Sub OnBtnMouseEnter(ByVal sender As Object, ByVal e As EventArgs)
    7.         Dim btn As Button
    8.         btn = DirectCast(sender, Button)
    9.         btn.BackgroundImage = Nothing
    10.         btn.BackColor = Color.WhiteSmoke
    11.  
    12.     End Sub
    13.  
    14.     Private Sub OnBtnMouseLeave(ByVal sender As Object, ByVal e As EventArgs)
    15.         Dim btn As Button
    16.         btn = DirectCast(sender, Button)
    17.         btn.BackgroundImage = My.Resources.btnBack
    18.         btn.BackgroundImageLayout = ImageLayout.Stretch
    19.  
    20.         Dim x As Integer = btn.Location.X
    21.         On Error Resume Next
    22.         x = x \ Me.ItemSize.Width
    23.  
    24.         If Me.SelectedTab Is Me.TabPages(x) Then
    25.             btn.BackgroundImage = Nothing
    26.             btn.BackColor = Color.FromKnownColor(KnownColor.ControlLightLight)
    27.         End If
    28.     End Sub
    29.  
    30.  
    31.     Private Sub onBtnMouseDown(ByVal sender As Object, ByVal e As EventArgs)
    32.         If MouseButtons = Windows.Forms.MouseButtons.Right Then
    33.             On Error Resume Next
    34.             Dim Index As Integer
    35.             Dim btn As Button
    36.             btn = DirectCast(sender, Button)
    37.             Dim x As Integer = btn.Location.X  
    38.             'you can also write the tab width in manually, mine was 115
    39.             Index = x \ Me.ItemSize.Width  '<--- Notice the integer division
    40.             Me.SelectedTab = Me.TabPages(Index)
    41.         End If
    42.  
    43.     End Sub
    44.  
    45.     Private Sub TabControlEx_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles Me.SelectedIndexChanged
    46.  
    47.         Dim btn As Button = CloseButtonOfTabPage(Me.SelectedTab)
    48.         btn.BackgroundImage = Nothing
    49.         btn.BackColor = Color.FromKnownColor(KnownColor.ControlLightLight)
    50.  
    51.         Dim lbl As Label = LabelOfTabPage(Me.SelectedTab)
    52.         lbl.BackgroundImage = Nothing
    53.         lbl.BackColor = Color.FromKnownColor(KnownColor.ControlLightLight)
    54.     End Sub
    55. End Class

    All of the code goes into the class- the code from this post and the post above.
    Last edited by Zombie666; May 19th, 2011 at 07:32 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width