none
Horizontal tabs bound on left of form RRS feed

  • Question

  • Hi there,

    I have an application where the requestor wants the tabs to be bound on the left of the form, instead of the top, which is the default. That part is easy enough, however, when I do this the tabs go into multiple rows (because I have some many of them) and are not presented in the way they want it after all. The user wants the tabs to read horizontally instead of vertically and look more or less like a stair case (for lack of a better visual reference) up along the left side of the Tab control.

    Any help would be greatly appreciated. Thanks! - ERic -

    Monday, March 26, 2007 6:21 PM

Answers

  • Set Drawmode to OwnerDrawFixed so that you can Draw the Text in the desired Orientation.
    Set SizeMode to Fixed.
    Set ItemSize to a size which will fit the Text.

     

    If you want VisualStyles then this is a little more work. Here's a Framework 2.0 class I started working on the last time I saw this question. It's not perfect, but it's not far off of what you want. Just add an instance to your form and set the ItemSize property as appropriate.

    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    
    Public Class MyTabControl
        Inherits TabControl
    
        Private tc As New TabControl
    
        Protected Overrides Sub OnCreateControl()
    
            MyBase.OnCreateControl()
    
            Me.DoubleBuffered = True
            Me.SetStyle(ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
    
            MyBase.SizeMode = TabSizeMode.Fixed
            tc.SizeMode = TabSizeMode.Fixed
            tc.CreateControl()
    
        End Sub
    
        <Browsable(False), EditorBrowsable(EditorBrowsableState.Never), _
        DefaultValue(GetType(TabSizeMode), "Fixed")> _
        Public Shadows ReadOnly Property SizeMode() As TabSizeMode
            Get
                Return TabSizeMode.Fixed
            End Get
        End Property
    
        Public Shadows Property ItemSize() As Size
            Get
                Return MyBase.ItemSize
            End Get
            Set(ByVal value As Size)
                MyBase.ItemSize = value
                tc.ItemSize = value
                Me.Invalidate()
            End Set
        End Property
    
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            MyBase.OnResize(e)
    
            If Application.RenderWithVisualStyles() Then
    
                tc.Alignment = TabAlignment.Top
                If Me.Alignment <= TabAlignment.Bottom Then
                    tc.Multiline = Me.Multiline
                    tc.Size = Me.Size
                Else
                    tc.Multiline = True
                    tc.Size = New Size(Me.Height, Me.Width)
                End If
            Else
                tc.Alignment = Me.Alignment
                tc.Multiline = Me.Multiline
                tc.Size = Me.Size
            End If
    
        End Sub
    
        Protected Overrides Sub OnLocationChanged(ByVal e As System.EventArgs)
            MyBase.OnLocationChanged(e)
            tc.Location = Me.Location
        End Sub
    
        Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs)
            MyBase.OnSelectedIndexChanged(e)
            tc.SelectedIndex = Me.SelectedIndex
            Me.Invalidate()
        End Sub
    
        Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaintBackground(pevent)
    
            Dim bm As New Bitmap(tc.Width, tc.Height)
    
            tc.DrawToBitmap(bm, New Rectangle(Point.Empty, tc.Size))
    
            If Application.RenderWithVisualStyles() Then
    
                If Me.Alignment = TabAlignment.Bottom Then
                    bm.RotateFlip(RotateFlipType.RotateNoneFlipY)
                ElseIf Me.Alignment = TabAlignment.Left Then
                    bm.RotateFlip(RotateFlipType.Rotate90FlipX)
                ElseIf Me.Alignment = TabAlignment.Right Then
                    bm.RotateFlip(RotateFlipType.Rotate90FlipNone)
                End If
            End If
    
            pevent.Graphics.DrawImage(bm, Point.Empty)
            bm.Dispose()
    
            Dim sf As New StringFormat
            sf.Alignment = StringAlignment.Center
            sf.LineAlignment = StringAlignment.Center
    
            Dim textBrush As New SolidBrush(Me.ForeColor)
    
            For Each tab As TabPage In Me.TabPages
                Dim tabRect As Rectangle = Me.GetTabRect(Me.TabPages.IndexOf(tab))
                pevent.Graphics.DrawString(tab.Text, Me.Font, textBrush, RectangleF.op_Implicit(tabRect), sf)
            Next
    
            textBrush.Dispose()
            sf.Dispose()
    
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    
            MyBase.WndProc(m)
    
            Select Case m.Msg
                Case TCM_DELETEITEM
                    If tc.Created Then
                        tc.TabPages.RemoveAt(m.WParam.ToInt32)
                    End If
                Case TCM_DELETEALLITEMS
                    If tc.Created Then
                        tc.TabPages.Clear()
                    End If
                Case TCM_INSERTITEMA, TCM_INSERTITEMW
                    If tc.Created Then
                        Dim tp As New TabPage
                        tp.UseVisualStyleBackColor = False
                        tc.TabPages.Add(tp)
                    End If
            End Select
    
        End Sub
    
    #Region " Interop Declarations "
    
        Private Const TCM_FIRST As Int32 = &H1300
        Private Const TCM_INSERTITEMA As Int32 = (TCM_FIRST + 7)
        Private Const TCM_INSERTITEMW As Int32 = (TCM_FIRST + 62)
        Private Const TCM_DELETEITEM As Int32 = (TCM_FIRST + 8)
        Private Const TCM_DELETEALLITEMS As Int32 = (TCM_FIRST + 9)
    
    #End Region
    
    End Class
    
    Monday, March 26, 2007 10:20 PM

All replies

  • What we want things to be, and the reality of what they are, rarely are the same.  The default TabControl just doesn't work that way.

    The easiest thing would probably be to find a third party custom control that does what you want.  Otherwise you'll have to create your own; and it would probably be quicker to create a control from scratch using panels and buttons than to try to modify the default behavior of the TabControl.

    Monday, March 26, 2007 7:00 PM
    Moderator
  • Set Drawmode to OwnerDrawFixed so that you can Draw the Text in the desired Orientation.
    Set SizeMode to Fixed.
    Set ItemSize to a size which will fit the Text.

     

    If you want VisualStyles then this is a little more work. Here's a Framework 2.0 class I started working on the last time I saw this question. It's not perfect, but it's not far off of what you want. Just add an instance to your form and set the ItemSize property as appropriate.

    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    
    Public Class MyTabControl
        Inherits TabControl
    
        Private tc As New TabControl
    
        Protected Overrides Sub OnCreateControl()
    
            MyBase.OnCreateControl()
    
            Me.DoubleBuffered = True
            Me.SetStyle(ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
    
            MyBase.SizeMode = TabSizeMode.Fixed
            tc.SizeMode = TabSizeMode.Fixed
            tc.CreateControl()
    
        End Sub
    
        <Browsable(False), EditorBrowsable(EditorBrowsableState.Never), _
        DefaultValue(GetType(TabSizeMode), "Fixed")> _
        Public Shadows ReadOnly Property SizeMode() As TabSizeMode
            Get
                Return TabSizeMode.Fixed
            End Get
        End Property
    
        Public Shadows Property ItemSize() As Size
            Get
                Return MyBase.ItemSize
            End Get
            Set(ByVal value As Size)
                MyBase.ItemSize = value
                tc.ItemSize = value
                Me.Invalidate()
            End Set
        End Property
    
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            MyBase.OnResize(e)
    
            If Application.RenderWithVisualStyles() Then
    
                tc.Alignment = TabAlignment.Top
                If Me.Alignment <= TabAlignment.Bottom Then
                    tc.Multiline = Me.Multiline
                    tc.Size = Me.Size
                Else
                    tc.Multiline = True
                    tc.Size = New Size(Me.Height, Me.Width)
                End If
            Else
                tc.Alignment = Me.Alignment
                tc.Multiline = Me.Multiline
                tc.Size = Me.Size
            End If
    
        End Sub
    
        Protected Overrides Sub OnLocationChanged(ByVal e As System.EventArgs)
            MyBase.OnLocationChanged(e)
            tc.Location = Me.Location
        End Sub
    
        Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs)
            MyBase.OnSelectedIndexChanged(e)
            tc.SelectedIndex = Me.SelectedIndex
            Me.Invalidate()
        End Sub
    
        Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaintBackground(pevent)
    
            Dim bm As New Bitmap(tc.Width, tc.Height)
    
            tc.DrawToBitmap(bm, New Rectangle(Point.Empty, tc.Size))
    
            If Application.RenderWithVisualStyles() Then
    
                If Me.Alignment = TabAlignment.Bottom Then
                    bm.RotateFlip(RotateFlipType.RotateNoneFlipY)
                ElseIf Me.Alignment = TabAlignment.Left Then
                    bm.RotateFlip(RotateFlipType.Rotate90FlipX)
                ElseIf Me.Alignment = TabAlignment.Right Then
                    bm.RotateFlip(RotateFlipType.Rotate90FlipNone)
                End If
            End If
    
            pevent.Graphics.DrawImage(bm, Point.Empty)
            bm.Dispose()
    
            Dim sf As New StringFormat
            sf.Alignment = StringAlignment.Center
            sf.LineAlignment = StringAlignment.Center
    
            Dim textBrush As New SolidBrush(Me.ForeColor)
    
            For Each tab As TabPage In Me.TabPages
                Dim tabRect As Rectangle = Me.GetTabRect(Me.TabPages.IndexOf(tab))
                pevent.Graphics.DrawString(tab.Text, Me.Font, textBrush, RectangleF.op_Implicit(tabRect), sf)
            Next
    
            textBrush.Dispose()
            sf.Dispose()
    
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    
            MyBase.WndProc(m)
    
            Select Case m.Msg
                Case TCM_DELETEITEM
                    If tc.Created Then
                        tc.TabPages.RemoveAt(m.WParam.ToInt32)
                    End If
                Case TCM_DELETEALLITEMS
                    If tc.Created Then
                        tc.TabPages.Clear()
                    End If
                Case TCM_INSERTITEMA, TCM_INSERTITEMW
                    If tc.Created Then
                        Dim tp As New TabPage
                        tp.UseVisualStyleBackColor = False
                        tc.TabPages.Add(tp)
                    End If
            End Select
    
        End Sub
    
    #Region " Interop Declarations "
    
        Private Const TCM_FIRST As Int32 = &H1300
        Private Const TCM_INSERTITEMA As Int32 = (TCM_FIRST + 7)
        Private Const TCM_INSERTITEMW As Int32 = (TCM_FIRST + 62)
        Private Const TCM_DELETEITEM As Int32 = (TCM_FIRST + 8)
        Private Const TCM_DELETEALLITEMS As Int32 = (TCM_FIRST + 9)
    
    #End Region
    
    End Class
    
    Monday, March 26, 2007 10:20 PM
  • Mick, Thanks for your help on this. Got another issue I have to deal with today, but I will work on implementing this later and see what happens. Thanks again! - Eric-
    Wednesday, March 28, 2007 4:07 PM