2011-09-21 19 views
14

我想让我的TabControl上的选项卡显示在左侧或右侧。
但是,与System.Windows.Forms.TabControl不同,我希望文本保持水平,而不是被水平旋转90度或270度。在Winforms中使用水平文本的垂直制表符控制

这里有几个图片说明概念 Vertical tabs in Visual Studio Vertical tabs in Firefox

虽然我可以编写代码来做到这一点我在大约一个小时或两个,我只是想我会先询问是否有任何现有的Winforms控件实现此功能。

注意:任何现有的解决方案应该最好是非商业的。

谢谢。

回答

21

我不知道如何健壮,这是我不能声称已经创造了它,但... http://www.dreamincode.net/forums/topic/125792-how-to-make-vertical-tabs/

下面是做这件事的方式。

所以首先我们要改变其左对齐,通过设置属性:

对齐=左

如果您有XP主题开启,那么你可能会注意到选项卡的怪异布局控制。别担心,我们会好起来的。

正如您可能已经注意到标签是垂直的,并且我们的要求是水平的。所以我们可以改变标签的大小。但是我们可以做到这一点之前,我们必须设置SizeMode属性为,

SizeMode =固定

现在我们可以通过使用ItemSize属性更改大小,

ItemSize = 30,120 Width = 30 and Height = 120

在设置Alignment = Left之后,Tab控件旋转导致宽度和高度似乎颠倒的Tabs。这就是为什么当我们增加高度时,我们看到宽度在增加,当我们增加宽度时,高度就会受到影响。

现在文本也将显示,但垂直。不幸的是,没有简单的方法来解决这个问题。为此,我们必须自己写文本。要做到这一点,我们将首先设置DrawMode

DrawMode = OwnerDrawFixed

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 
+0

感谢您的帮助。我稍微调整了一下代码,但没有从头开始写一个新的控件。 –

+0

@AlexEssilfie是否让您看起来与您包含的截图完全相同?如果是这样,你可以分享代码吗? –

+0

@AmitAndharia:我并不希望它完全如屏幕截图所示,但我能够很好地为它工作。为了更广泛的社区利益,我会在今天晚些时候或最多三天内上传我的代码。 –

4

我决定分享我因为一些人开发的代码,如Amit Andharia,想从中受益。

这是我执行Rob P.'s answer后的结果。

Vertical Tabs Control screenshot

发行说明:

  • 全部设计时支持
  • (最多128像素宽)
  • 标签的自动调整大小
  • 标签的图标实现
  • 未使用的属性已经隐藏

该代码可以从here下载。

+0

谢谢亚历克斯。我一直认为它与你发布的截图类似,因此有兴趣查看代码,无论你分享的代码是否真的有帮助。 –

+1

@AmitAndharia:我写了一个复制Visual Studio样式的代码,但不幸丢失了代码,所以我不得不修复这个代码并将它打包成一个'.vb'文件以供使用。如果你愿意,我可以重新实现VS风格的,但我不能保证很快得到它。 –

+0

谢谢你,如果你可以做类似的事情,并分享,这将是gr8。 –

0

Microsoft提供了一个教程,用于使用现有的TabControl MSDN执行此操作,同时在C#和Visual Basic .NET中给出示例代码。他们的方法基于使用所有者绘图。下面总结他们的步骤:

  1. 的TabControl的的对准属性设置为

  2. 确保所有选项卡是相同的水平宽度通过设置SizeMode属性固定

  3. 设置ItemSize属性为标签的首选大小,牢记宽度和高度颠倒

  4. 设置DrawMode属性OwnerDrawFixed

  5. 为TabControl的DrawItem事件设置事件处理程序,并将您的所有者绘图代码放在那里,指示应该如何显示每个标签。他们对事件处理程序的C#示例代码复制到下面以方便(它假定您的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值细末-tune你的标签外观无论你需要更炫的造型,我建议你看this other MSDN article为起点

(来源:How to: Display Side-Aligned Tabs with TabControl (MSDN))。

+0

你读过[Rob P.的答案](http://stackoverflow.com/a/7501638)吗?在他发布他的答案近六年后,你已经重复了**完全相同的事情。 –

+0

@AlexEssilfie我不会说完全一样的。首先,我提供的代码是用C#编写的,而他的代码是用VB.NET提供的。其次,我使用MSDN作为我的源代码,而不是从其他地方发布的论坛帖子,所以我想我提供的代码版本更可能代表接近这个的最佳实践。第三,如果你喜欢查看(使用'GetTabRect()'而不是'e.Bounds',代码来说明所选状态等),代码中就会有细微的差异。基本上,我发布了我的答案,因为我相信我必须分享的信息更完整,质量更高。 –

0

这是我非常喜欢的自定义选项卡控件的代码。您需要将此代码复制并粘贴到新类中,然后重新构建该项目。您会在工具箱中看到新的自定义用户控件。

Vertical Tab Control with Indicator and 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