Управление вертикальной вкладкой с горизонтальным текстом в Winforms

Я бы хотел, чтобы вкладки на моем TabControl отображались слева или иногда правильно.
Однако, в отличие от System.Windows.Forms.TabControl, я бы хотел, чтобы текст оставался горизонтальным вместо поворота на 90 или 270 градусов по горизонтали.

Вот пара фотографий, иллюстрирующих концепцию Vertical tabs in Visual StudioVertical tabs in Firefox

Хотя я мог написать код, чтобы сделать это сам примерно через час или два, я просто подумал, что сначала спрошу, есть ли какой-либо существующий элемент управления Winforms, который реализует такую ​​функцию.

NB: Любое существующее решение должно быть предпочтительно некоммерческим.

Спасибо.

Ответы

Ответ 1

Я не знаю, насколько это здорово, и я не могу утверждать, что создал его, но... http://www.dreamincode.net/forums/topic/125792-how-to-make-vertical-tabs/

Вот как это сделать.

Итак, сначала мы изменим его выравнивание налево, установив свойство:

Выравнивание = левый

Если у вас включены темы XP, вы можете заметить странный макет Tab Control. Не беспокойтесь, мы сделаем это хорошо.

Как вы могли заметить, что вкладки вертикальные, а наше требование - горизонтальное. Таким образом, мы можем изменить размер вкладок. Но прежде чем мы сможем сделать это, мы должны установить свойство SizeMode как,

SizeMode = Исправлено

Теперь мы можем изменить размер с помощью свойства ItemSize,

ItemSize = 30, 120 Ширина = 30 и Высота = 120

После установки выравнивания = Влево, элемент управления Tab поворачивает вкладки, из-за которых ширина и высота кажутся противоположными. Поэтому, когда мы увеличиваем высоту, мы видим, что ширина увеличивается, и когда мы увеличиваем ширину, выполняется высота.

Теперь текст будет отображаться, но вертикально. К сожалению, нет простого способа решить эту проблему. Для этого мы должны сами написать текст. Для этого мы сначала установим DrawMode

DrawMode = OwnerDrawFixed

01

Private Sub TabControl1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
    Dim g As Graphics
    Dim sText As String

    Dim iX As Integer
    Dim iY As Integer
    Dim sizeText As SizeF

    Dim ctlTab As TabControl

    ctlTab = CType(sender, TabControl)

    g = e.Graphics

    sText = ctlTab.TabPages(e.Index).Text
    sizeText = g.MeasureString(sText, ctlTab.Font)

    iX = e.Bounds.Left + 6
    iY = e.Bounds.Top + (e.Bounds.Height - sizeText.Height) / 2

    g.DrawString(sText, ctlTab.Font, Brushes.Black, iX, iY)
End Sub

Ответ 2

Я решил поделиться кодом, который я разработал, поскольку некоторые люди, такие как Amit Andharia, хотели бы извлечь из этого выгоду.

Это результат после того, как я внедрил Rob P. answer.

Vertical Tabs Control screenshot

Примечания к выпуску:

  • Полная поддержка времени разработки
  • Автоматическое изменение размеров вкладок (до 128 пикселей в ширину)
  • Значки вкладки реализованы
  • Неиспользуемые свойства были скрыты

Код можно скачать с здесь.

Ответ 3

Существует учебник, предоставленный Microsoft для этого с существующим TabControl на MSDN, с образцом кода, указанным как в С#, так и в Visual Basic.NET. Их метод основан на использовании чертежа владельца. Подводя следующие шаги:

  • Установите свойство TabControl Выравнивание в Вправо.

  • Убедитесь, что все вкладки имеют одинаковую ширину горизонтали, установив для свойства SizeMode значение Исправлено.

  • Задайте свойство ItemSize для вашего предпочтительного размера для вкладок, имея в виду, что ширина и высота меняются на противоположные.

  • Установите для свойства DrawMode значение OwnerDrawFixed.

  • Настройте обработчик событий для события TabControl DrawItem и поместите в него код чертежа владельца, определяющий, как должна отображаться каждая вкладка. Их пример кода С# для обработчика событий воспроизводится ниже для удобства (предполагается, что ваш TabControl имеет имя tabControl1:

    private void tabControl1_DrawItem(Object sender, System.Windows.Forms.DrawItemEventArgs e)
    {
        Graphics g = e.Graphics;
        Brush _textBrush;
    
        // Get the item from the collection.
        TabPage _tabPage = tabControl1.TabPages[e.Index];
    
        // Get the real bounds for the tab rectangle.
        Rectangle _tabBounds = tabControl1.GetTabRect(e.Index);
    
        if (e.State == DrawItemState.Selected)
        {
    
            // Draw a different background color, and don't paint a focus rectangle.
            _textBrush = new SolidBrush(Color.Red);
            g.FillRectangle(Brushes.Gray, e.Bounds);
        }
        else
        {
            _textBrush = new System.Drawing.SolidBrush(e.ForeColor);
            e.DrawBackground();
        }
    
        // Use our own font.
        Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
    
        // Draw string. Center the text.
        StringFormat _stringFlags = new StringFormat();
        _stringFlags.Alignment = StringAlignment.Center;
        _stringFlags.LineAlignment = StringAlignment.Center;
        g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
    }
    

Возможно, вы экспериментируете со своим свойством ItemSize и значением _tabFont из приведенного выше кода, чтобы тонко настроить внешний вид ваших вкладок на все, что вам нужно. Для даже более увлекательного стиля я бы рекомендовал в качестве отправной точки взглянуть на эту другую статью MSDN.

(Источник: Практическое руководство. Отображение вкладок с двусторонним выравниванием с помощью TabControl (MSDN))

Ответ 4

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

Управление вертикальной вкладкой с индикатором и ImageList

    Imports System.Drawing.Drawing2D
Class DotNetBarTabcontrol
    Inherits TabControl

    Sub New()
        SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True)
        DoubleBuffered = True
        SizeMode = TabSizeMode.Fixed
        ItemSize = New Size(44, 136)
    End Sub
    Protected Overrides Sub CreateHandle()
        MyBase.CreateHandle()
        Alignment = TabAlignment.Left
    End Sub

    Function ToPen(ByVal color As Color) As Pen
        Return New Pen(color)
    End Function

    Function ToBrush(ByVal color As Color) As Brush
        Return New SolidBrush(color)
    End Function

    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
        Dim B As New Bitmap(Width, Height)
        Dim G As Graphics = Graphics.FromImage(B)
        Try : SelectedTab.BackColor = Color.White : Catch : End Try
        G.Clear(Color.White)
        G.FillRectangle(New SolidBrush(Color.FromArgb(246, 248, 252)), New Rectangle(0, 0, ItemSize.Height + 4, Height))
        'G.DrawLine(New Pen(Color.FromArgb(170, 187, 204)), New Point(Width - 1, 0), New Point(Width - 1, Height - 1))    'comment out to get rid of the borders
        'G.DrawLine(New Pen(Color.FromArgb(170, 187, 204)), New Point(ItemSize.Height + 1, 0), New Point(Width - 1, 0))                   'comment out to get rid of the borders
        'G.DrawLine(New Pen(Color.FromArgb(170, 187, 204)), New Point(ItemSize.Height + 3, Height - 1), New Point(Width - 1, Height - 1)) 'comment out to get rid of the borders
        G.DrawLine(New Pen(Color.FromArgb(170, 187, 204)), New Point(ItemSize.Height + 3, 0), New Point(ItemSize.Height + 3, 999))
        For i = 0 To TabCount - 1
            If i = SelectedIndex Then
                Dim x2 As Rectangle = New Rectangle(New Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2), New Size(GetTabRect(i).Width + 3, GetTabRect(i).Height - 1))
                Dim myBlend As New ColorBlend()
                myBlend.Colors = {Color.FromArgb(232, 232, 240), Color.FromArgb(232, 232, 240), Color.FromArgb(232, 232, 240)}
                myBlend.Positions = {0.0F, 0.5F, 1.0F}
                Dim lgBrush As New LinearGradientBrush(x2, Color.Black, Color.Black, 90.0F)
                lgBrush.InterpolationColors = myBlend
                G.FillRectangle(lgBrush, x2)
                G.DrawRectangle(New Pen(Color.FromArgb(170, 187, 204)), x2)


                G.SmoothingMode = SmoothingMode.HighQuality
                Dim p() As Point = {New Point(ItemSize.Height - 3, GetTabRect(i).Location.Y + 20), New Point(ItemSize.Height + 4, GetTabRect(i).Location.Y + 14), New Point(ItemSize.Height + 4, GetTabRect(i).Location.Y + 27)}
                G.FillPolygon(Brushes.White, p)
                G.DrawPolygon(New Pen(Color.FromArgb(170, 187, 204)), p)

                If ImageList IsNot Nothing Then
                    Try
                        If ImageList.Images(TabPages(i).ImageIndex) IsNot Nothing Then

                            G.DrawImage(ImageList.Images(TabPages(i).ImageIndex), New Point(x2.Location.X + 8, x2.Location.Y + 6))
                            G.DrawString("      " & TabPages(i).Text, Font, Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                        Else
                            G.DrawString(TabPages(i).Text, New Font(Font.FontFamily, Font.Size, FontStyle.Bold), Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                        End If
                    Catch ex As Exception
                        G.DrawString(TabPages(i).Text, New Font(Font.FontFamily, Font.Size, FontStyle.Bold), Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                    End Try
                Else
                    G.DrawString(TabPages(i).Text, New Font(Font.FontFamily, Font.Size, FontStyle.Bold), Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                End If

                G.DrawLine(New Pen(Color.FromArgb(200, 200, 250)), New Point(x2.Location.X - 1, x2.Location.Y - 1), New Point(x2.Location.X, x2.Location.Y))
                G.DrawLine(New Pen(Color.FromArgb(200, 200, 250)), New Point(x2.Location.X - 1, x2.Bottom - 1), New Point(x2.Location.X, x2.Bottom))
            Else
                Dim x2 As Rectangle = New Rectangle(New Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2), New Size(GetTabRect(i).Width + 3, GetTabRect(i).Height + 1))
                G.FillRectangle(New SolidBrush(Color.FromArgb(246, 248, 252)), x2)
                G.DrawLine(New Pen(Color.FromArgb(170, 187, 204)), New Point(x2.Right, x2.Top), New Point(x2.Right, x2.Bottom))
                If ImageList IsNot Nothing Then
                    Try
                        If ImageList.Images(TabPages(i).ImageIndex) IsNot Nothing Then
                            G.DrawImage(ImageList.Images(TabPages(i).ImageIndex), New Point(x2.Location.X + 8, x2.Location.Y + 6))
                            G.DrawString("      " & TabPages(i).Text, Font, Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                        Else
                            G.DrawString(TabPages(i).Text, Font, Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                        End If
                    Catch ex As Exception
                        G.DrawString(TabPages(i).Text, Font, Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                    End Try
                Else
                    G.DrawString(TabPages(i).Text, Font, Brushes.DimGray, x2, New StringFormat With {.LineAlignment = StringAlignment.Center, .Alignment = StringAlignment.Center})
                End If
            End If
        Next

        e.Graphics.DrawImage(B.Clone, 0, 0)
        G.Dispose() : B.Dispose()
    End Sub
End Class