locked
How to make the label rotated in vb.net RRS feed

  • 问题

  • Hi Everyone 

    I need some help here, i having a problem making the label rotate the angle to 90 degrees. 

    can anyone here can help me up with this i totally have no ideal at all.

    Thank You

    Johnny

    2015年10月10日 14:19

答案

  • You can't rotate a label - but that doesn't matter because you don't really need them.

    Just draw the text direct to the form (or other container) using something like this:

       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          ' move graphics origin to where you want the label
          e.Graphics.TranslateTransform(100, 100)
          ' rotate it 90 degrees
          e.Graphics.RotateTransform(90)
          ' draw the text
          e.Graphics.DrawString("Label text", Font, Brushes.Black, New Point(0, 0))
       End Sub
    

    • 已标记为答案 CalebJohnny 2015年10月10日 15:06
    2015年10月10日 14:27
  • The graphics transforms are cumulative so you will either need to keep track of them or reset them after drawing each label.  Resetting is easiest with e.graphics.restore

    If you have a number of labels you may wish to create a small class to handle them and store them in a list which simplifies the paint event handler.

    The following would serve as a starting point - try it in a new project.

    Imports System.Drawing.Drawing2D
    Public Class Form1
       Dim Label1 As myLabel
       Dim Label2 As myLabel
       Dim Label3 As myLabel
       Dim myLabels As New List(Of myLabel)
       Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
          Label1 = New myLabel("Label1", New Point(50, 50))
          myLabels.Add(Label1)
          Label2 = New myLabel("Label2", New Point(100, 100), 45)
          myLabels.Add(Label2)
          Label3 = New myLabel("Label3", New Point(200, 100), 90, New Font("Arial", 18), Color.Blue)
          myLabels.Add(Label3)
       End Sub
       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          For Each Lbl As myLabel In myLabels
             Lbl.Draw(e.Graphics)
          Next
       End Sub
    End Class
    
    
    Public Class myLabel
       Public Property Text As String
       Public Property Location As Point
       Public Property Angle As Integer
       Public Property Font As Font
       Public Property ForeColour As Color
       Public Sub New(Text As String, Location As Point)
          Me.New(Text, Location, 0, New Font("Arial", 10), Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer)
          Me.New(Text, Location, Angle, New Font("Arial", 10), Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer, Font As Font)
          Me.New(Text, Location, Angle, Font, Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer, Font As Font, ForeColour As Color)
          Me.Text = Text
          Me.Location = Location
          Me.Angle = Angle
          Me.Font = Font
          Me.ForeColour = ForeColour
       End Sub
       Public Sub Draw(g As Graphics)
          Dim State As GraphicsState = g.Save
          g.TranslateTransform(Location.X, Location.Y)
          g.RotateTransform(Angle)
          Using Brsh As New SolidBrush(ForeColour)
             g.DrawString(Text, Font, Brsh, New Point(0, 0))
          End Using
          g.Restore(State)
       End Sub
    End Class

    • 已标记为答案 CalebJohnny 2015年10月10日 17:04
    2015年10月10日 15:49
  • Using forms paint event you can ResetTransform after each drawn string. Then set "e.Graphics.TranslateTransform" and "e.Graphics.RotateTransform" for the next string then draw the next string.

       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          ' move graphics origin to where you want the label
          e.Graphics.TranslateTransform(100, 100)
          ' rotate it 90 degrees
          e.Graphics.RotateTransform(90)
          ' draw the text
          e.Graphics.DrawString("Label text", Font, Brushes.Black, New Point(0, 0))
          e.Graphics.ResetTransform()
       End Sub


    La vida loca

    • 已标记为答案 CalebJohnny 2015年10月10日 17:03
    2015年10月10日 16:01

全部回复

  • You can't rotate a label - but that doesn't matter because you don't really need them.

    Just draw the text direct to the form (or other container) using something like this:

       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          ' move graphics origin to where you want the label
          e.Graphics.TranslateTransform(100, 100)
          ' rotate it 90 degrees
          e.Graphics.RotateTransform(90)
          ' draw the text
          e.Graphics.DrawString("Label text", Font, Brushes.Black, New Point(0, 0))
       End Sub
    

    • 已标记为答案 CalebJohnny 2015年10月10日 15:06
    2015年10月10日 14:27
  • Hi Dave

    okay what if i have 3 more label need to rotate the text still able to do in form paint event?

    if that so how am i going to do that.

    Thank you

    Johnny

    2015年10月10日 14:32
  • Johnny,

    Be aware VB has no labels, you can use endless labels in VB therefore tell which technology you are using for presentation. 

    Most common in VB for desktop are Windows Forms and WPF, but you can also simply paint them on a presentation layer.

    Also it is important to know what you want with the characters inside it. Putting your screen on its side is not such a nice way you know.


    Success
    Cor


    2015年10月10日 14:36
  • Hi Dave

    okay what if i have 3 more label need to rotate the text still able to do in form paint event?

    if that so how am i going to do that.

    Thank you

    Johnny

    Didn't Dave299 advise the you can not rotate a Windows.Forms Label? Now you have 3 more Labels you are asking about for some reason even though you can not rotate a Windows.Forms Label.

    Maybe you should use PictureBox's since you can draw strings in them and rotate the strings. And provide each PictureBox with its own paint event.

    If you want to rotate controls then use WPF not Windows.Forms.

    WPF Tutorial - Part 1 : Transformations

    Image with rotated ListBox in WPF.


    La vida loca

    2015年10月10日 14:44
  • Hi MonkeyBoy 

    Yes i know cant rotate the label sorry if i never write clearly is if i have 3 more string to display

    in different location and string.


    Thank You

    Johnny 


    2015年10月10日 15:02
  • The graphics transforms are cumulative so you will either need to keep track of them or reset them after drawing each label.  Resetting is easiest with e.graphics.restore

    If you have a number of labels you may wish to create a small class to handle them and store them in a list which simplifies the paint event handler.

    The following would serve as a starting point - try it in a new project.

    Imports System.Drawing.Drawing2D
    Public Class Form1
       Dim Label1 As myLabel
       Dim Label2 As myLabel
       Dim Label3 As myLabel
       Dim myLabels As New List(Of myLabel)
       Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
          Label1 = New myLabel("Label1", New Point(50, 50))
          myLabels.Add(Label1)
          Label2 = New myLabel("Label2", New Point(100, 100), 45)
          myLabels.Add(Label2)
          Label3 = New myLabel("Label3", New Point(200, 100), 90, New Font("Arial", 18), Color.Blue)
          myLabels.Add(Label3)
       End Sub
       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          For Each Lbl As myLabel In myLabels
             Lbl.Draw(e.Graphics)
          Next
       End Sub
    End Class
    
    
    Public Class myLabel
       Public Property Text As String
       Public Property Location As Point
       Public Property Angle As Integer
       Public Property Font As Font
       Public Property ForeColour As Color
       Public Sub New(Text As String, Location As Point)
          Me.New(Text, Location, 0, New Font("Arial", 10), Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer)
          Me.New(Text, Location, Angle, New Font("Arial", 10), Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer, Font As Font)
          Me.New(Text, Location, Angle, Font, Color.Black)
       End Sub
       Public Sub New(Text As String, Location As Point, Angle As Integer, Font As Font, ForeColour As Color)
          Me.Text = Text
          Me.Location = Location
          Me.Angle = Angle
          Me.Font = Font
          Me.ForeColour = ForeColour
       End Sub
       Public Sub Draw(g As Graphics)
          Dim State As GraphicsState = g.Save
          g.TranslateTransform(Location.X, Location.Y)
          g.RotateTransform(Angle)
          Using Brsh As New SolidBrush(ForeColour)
             g.DrawString(Text, Font, Brsh, New Point(0, 0))
          End Using
          g.Restore(State)
       End Sub
    End Class

    • 已标记为答案 CalebJohnny 2015年10月10日 17:04
    2015年10月10日 15:49
  • Using forms paint event you can ResetTransform after each drawn string. Then set "e.Graphics.TranslateTransform" and "e.Graphics.RotateTransform" for the next string then draw the next string.

       Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
          ' move graphics origin to where you want the label
          e.Graphics.TranslateTransform(100, 100)
          ' rotate it 90 degrees
          e.Graphics.RotateTransform(90)
          ' draw the text
          e.Graphics.DrawString("Label text", Font, Brushes.Black, New Point(0, 0))
          e.Graphics.ResetTransform()
       End Sub


    La vida loca

    • 已标记为答案 CalebJohnny 2015年10月10日 17:03
    2015年10月10日 16:01
  • Hi All

    Thank you all for helping me i will try all the code see which one suit me the best thank.

    Thank you

    Johnny

    2015年10月10日 17:05
  •  If you have several labels that you want the text rotated in, then you could add a small class to your project like the one below.  Then Build your project.  After Building your project,  you will see the MyLabel class in the top of your ToolBox.  You can add as many as you want to the Form and set their TextAngle property to any angle between 0 and 359 degrees.

    Public Class Form1
    
    End Class
    
    Public Class MyLabel
        Inherits Control
    
        Private _TextAngle As Integer = 0
    
        Public Sub New()
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.SupportsTransparentBackColor, True)
            Me.SetStyle(ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
            Me.SetStyle(ControlStyles.Selectable, False)
        End Sub
    
        Public Property TextAngle() As Integer
            Get
                Return _TextAngle
            End Get
            Set(ByVal value As Integer)
                If value > 359 Then value = 359
                If value < 0 Then value = 0
                _TextAngle = value
                Me.Refresh()
            End Set
        End Property
    
        Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
            MyBase.OnTextChanged(e)
            Me.Refresh()
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
            With e.Graphics
                .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
                Dim pf As New PointF(CSng(Me.ClientSize.Width / 2), CSng(Me.ClientSize.Height / 2))
                .TranslateTransform(pf.X, pf.Y)
                .RotateTransform(_TextAngle)
                .TranslateTransform(-pf.X, -pf.Y)
                Using sf As New StringFormat With {.Alignment = StringAlignment.Center, .LineAlignment = StringAlignment.Center, .FormatFlags = StringFormatFlags.NoWrap}
                    Using sb As New SolidBrush(Me.ForeColor)
                        .DrawString(Me.Text, Me.Font, sb, New Rectangle(0, 0, Me.Width, Me.Height), sf)
                    End Using
                End Using
                .ResetTransform()
            End With
        End Sub
    End Class
    

     

     Here is the label with the angles set to 0, 45, 90, 135, 180, 225, 270, and 315.


    If you say it can`t be done then i`ll try it

    2015年10月10日 18:59
  • You guys are too fast!

    Here is mine. I inherit a label. It auto-sizes the outline.

    I cant figure why it crashes when I try to create one from the toolbox?

    --------------------------------------------------------------------------

    Edit: Now works from toolbar but still not working properly.

    Edit 2: Worked out the bounding rectangle for the rotated label (black clientrectangle outline).


    'draw rotated label class draws text on form
    Imports System.Drawing.Drawing2D
    
    Public Class Form6
        Private WithEvents Label1 As New xLabel3(90, New Point(20, 50), "Rotate Label 1", Color.SkyBlue, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label2 As New xLabel3(45, New Point(70, 50), "Rotate Label 2", Color.BurlyWood, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label3 As New xLabel3(22.5, New Point(120, 50), "Rotate Label 3", Color.Firebrick, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label4 As New xLabel3(0, New Point(170, 50), "Rotate Label 4", Color.Violet, Color.White, New Font("Arial", 18, FontStyle.Bold))
    
        Private Sub Form7_Load(sender As Object, e As EventArgs) Handles Me.Load
            Label1.BorderStyle = BorderStyle.FixedSingle
            Label2.BorderStyle = BorderStyle.FixedSingle
            Label3.BorderStyle = BorderStyle.FixedSingle
            Label4.BorderStyle = BorderStyle.FixedSingle
        End Sub
    
        Private Sub Form6_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            Label1.Draw(e.Graphics)
            Label2.Draw(e.Graphics)
            Label3.Draw(e.Graphics)
            Label4.Draw(e.Graphics)
        End Sub
    End Class
    Public Class xLabel3
        Inherits Label
    
        Public rect As Rectangle
        Public rotation As Single
    
        Public Sub New()
            SetSize()
        End Sub
    
        Public Sub New(_rotation As Single, _Location As Point, _Text As String, _BackColor As Color, _ForeColor As Color, _Font As Font)
            rotation = _rotation
            Location = _Location
            Text = _Text
            BackColor = _BackColor
            ForeColor = _ForeColor
            Font = _Font
    
            SetSize()
        End Sub
        Private Sub SetSize()
            AutoSize = False
            Dim w As Size = TextRenderer.MeasureText(Text, Font, New Size(Integer.MaxValue, Integer.MaxValue))
    
            rect = New Rectangle(0, 0, w.Width, w.Height)
             Size = New Size(CInt((w.Height * Math.Sin(rotation / 57.4)) + w.Width - (w.Width * (1 - Math.Cos(rotation / 57.3)))), CInt((w.Height * Math.Cos(rotation / 57.3)) + (w.Width * Math.Sin(rotation / 57.3))))
        End Sub
        Public Sub Draw(g As Graphics)
            Dim gContainer As Drawing2D.GraphicsContainer
            gContainer = g.BeginContainer()
    
            g.SmoothingMode = SmoothingMode.AntiAlias
            g.TranslateTransform(Location.X, Location.Y)
    
            If BorderStyle = BorderStyle.FixedSingle Then
                g.DrawRectangle(New Pen(Color.Black, 1), Me.ClientRectangle)
            End If
    
            Using mx As New Matrix
                mx.Translate(Location.X, Location.Y)
                mx.RotateAt(rotation, New PointF(CSng(rect.Height * Math.Sin(rotation / 57.3)), 0))
                g.Transform = mx
            End Using
    
            g.TranslateTransform(CSng(rect.Height * Math.Sin(rotation / 57.3)), 0)
            g.FillRectangle(New SolidBrush(Me.BackColor), rect)
            g.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), 0, 0)
    
            g.EndContainer(gContainer)
        End Sub
    End Class

    2015年10月10日 20:40
  • @ Tom,

     It crashes because when you add a New Label to the Form the constructor is called to create the New Label on the form.  However, it calls a constructor with no parameters.  You would need to add another constructor with no parameters like this that it can use.

    Public Sub New()
    End Sub

     However,  you would need to have some Default values added to the Rect and Rotation variables or set some default values to them in the empty constructor.


    If you say it can`t be done then i`ll try it

    2015年10月10日 21:29

  •  However,  you would need to have some Default values added to the Rect and Rotation variables or set some default values to them in the empty constructor.


    Razerz,

    Yeah... I see...now I cant figure how to calc the control [clientrectangle] outline with rotation when the toolbar is used. I need to set the values somehow but rotation is not defined or is zero when New() is called.

    Just one more, how do I tell it the control drawing is handled so it does not draw the mybase text etc?

    See my updated example above.

    PS You can see the label at upper right (made in code) has the correct size [clientrectangle] outline but the lower left (from tool bar) does not.

    PSS I guess I have to define rotation with get and etc like you did? Makes ones brain tired.


    • 已编辑 tommytwotrain 2015年10月10日 22:25 [clientrectangle]
    2015年10月10日 22:03
  • @Tom

    I couldn't figure out how your example worked and didn't suffer from the same problem that IronRazerz' does in that if you put the labels too close together then they obscure each other.

    Then I realised that although you are defining the label as a control you are not adding them to the form's controls collection.  Inheriting from Label is simply giving you access to the inherited properties Location, Text, BackColor etc.  You could remove the inherits and define those properties in your own class but then you would finish up with much the same solution as I posted.

    Once you try and modify your class to work with the designer you are going to be adding them to the controls collection and will have the same problem that IronRazerz has and the bounds of the control will obscure anything behing it.
    2015年10月10日 22:33
  • Well, that is going to take a bit different of an approach.  You would not be able to stop the Border,  Backcolor,  Image,  or BackgroundImage from being drawn if you set those properties of the ExLabel.  However,  you can stop the Text from being drawn by using the OnPaint overrides sub of the ExLabel and removing the line that calls the OnPaint method of the Base class.  You would also need to set the UserPaint style of the class too.

    Public Class Lbl
        Inherits Label
    
        Public Sub New()
            Me.SetStyle(ControlStyles.UserPaint, True)
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    
            'MyBase.OnPaint(e) 'get rid of this line to stop the default text from being drawn
    
            'Draw the Text how you want it here....
    
        End Sub
    End Class
     

     This is the problem with Inheriting controls like Labels,  TextBoxes,  and some other controls.  You only have just so much control over modifying the way they are drawn or how they act.  You would need to hide/remove the Border,  Backcolor,  Image,  BackgroundImage and some other properties and then add your own properties for them so you can control the way things look and act.  Otherwise,  if someone uses the control they might try setting those properties which you see what would happen if they did.


    If you say it can`t be done then i`ll try it

    2015年10月10日 22:54
  • Dave,

    You are right I was not adding the code made labels to the form. I added that and to my dismay now the label backgrounds are all drawn where before they were not. Funny that. Its a new "feature" !

    I realize the class you show is basically doing the same thing. I was just trying to use a label for no good reason other than I figured Razer had already done it. :)

    At first just in the label paint event with no class and on and on...

    I was trying to add the clientrectangle to the object which I dont think you did in the class. Then I got off to working in the toolbar and etc.


    Razerz,

    So do you mean one cant suppress the mybase drawing of a label control? I have it setup using onpaint with no mybase but it stills seems to draw it all.

    As you can see adding the controls to the form makes it paint the label background now. I want to turn that off. Seems you just e.handled = true at the right moment?

    PS I guess since I was not adding the label1 etc to the form it was just a class as in Dave's example. Once added to form it gets the background drawn as mybase etc.

    2015年10月10日 23:59
  • Tom

    If you want to experiment with this further I would suggest inheriting from control, which gives you a drawing surface without any of the baggage you get from inheriting a label, and then redefine the region for the control to get round the overlapping problem.  Also move the drawing code into the OnPaint override rather than using a method which accepts the forms graphics.

    2015年10月11日 0:22
  • Tom

    If you want to experiment with this further I would suggest inheriting from control, which gives you a drawing surface without any of the baggage you get from inheriting a label, and then redefine the region for the control to get round the overlapping problem.  Also move the drawing code into the OnPaint override rather than using a method which accepts the forms graphics.

    Actually I did that and that's what made the last image above where the green background is drawn (by the system). Here it is again with my latest code.

    I am not sure how to do the region. I put in in formload? Should it be a class property instead?

    It is just an experiment for fun for whomever is interested of course.

    Edit: updated bounding box clientrectangle.

    'rotate label class example inherits control 
    Option Strict On
    Imports System.Drawing.Drawing2D
    Public Class Form8
        Private WithEvents Label4 As New xLabel(0, New Point(170, 50), "Rotate Label 4", Color.Teal, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label3 As New xLabel(25, New Point(120, 50), "Rotate Label 3", Color.Teal, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label2 As New xLabel(45, New Point(70, 50), "Rotate Label 2", Color.Teal, Color.White, New Font("Arial", 18, FontStyle.Bold))
        Private WithEvents Label1 As New xLabel(90, New Point(20, 50), "Rotate Label 1", Color.Teal, Color.White, New Font("Arial", 18, FontStyle.Bold))
    
        Private Sub Form6_Load(sender As Object, e As EventArgs) Handles Me.Load
            Controls.Add(Label4)
            Controls.Add(Label3)
            Controls.Add(Label2)
            Controls.Add(Label1)
    
            'this label control was added using tool bar
            'the rotation is set on the tool bar to 45
            'testLabel1.Rotation = 45
            testLabel1.BackColor = Color.White
            testLabel1.ForeColor = Color.Teal
            testLabel1.Font = New Font("Arial", 18, FontStyle.Bold)
            testLabel1.Location = New Point(200, 200)
            testLabel1.Text = "Tool Box testLabel1"
    
            'Label1.Region = New Region(Label1.ClientRectangle)
            'Label2.Region = New Region(Label2.ClientRectangle)
            'Label3.Region = New Region(Label3.ClientRectangle)
        End Sub
    
        Private Sub Form6_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            Me.Invalidate()
        End Sub
    End Class
    
    Public Class xLabel
        Inherits Control  'Label
        Public rect As Rectangle
        Public _Rotation As Single
    
        Public Sub New()
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.SupportsTransparentBackColor, True)
            Me.SetStyle(ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
            Me.SetStyle(ControlStyles.Selectable, False)
            SetSize()
        End Sub
    
        Public Sub New(Rotation As Single, _Location As Point, _Text As String, _BackColor As Color, _ForeColor As Color, _Font As Font)
            _Rotation = Rotation
            Location = _Location
            Text = _Text
            BackColor = _BackColor
            ForeColor = _ForeColor
            Font = _Font
            SetSize()
        End Sub
    
        Private Sub SetSize()
            AutoSize = False
            Dim w As Size = TextRenderer.MeasureText(Text, Font, New Size(Integer.MaxValue, Integer.MaxValue))
            rect = New Rectangle(0, 0, w.Width, w.Height)
            Size = New Size(CInt((w.Height * Math.Sin(Rotation / 57.4)) + w.Width - (w.Width * (1 - Math.Cos(Rotation / 57.3)))), CInt((w.Height * Math.Cos(Rotation / 57.3)) + (w.Width * Math.Sin(Rotation / 57.3))))
        End Sub
    
        Public Property Rotation() As Single
            Get
                Return _Rotation
            End Get
            Set(ByVal value As Single)
                If value > 359 Then value = 359
                If value < 0 Then value = 0
                _Rotation = value
                Me.Refresh()
            End Set
        End Property
    
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            'MyBase.OnPaint(e) 'get rid of this line to stop the default text from being drawn
    
            With e.Graphics
                Dim gContainer As Drawing2D.GraphicsContainer
                gContainer = .BeginContainer()
                .SmoothingMode = SmoothingMode.AntiAlias
    
                .DrawRectangle(New Pen(Color.AliceBlue, 2), Me.ClientRectangle)
    
                Using mx As New Matrix
                    mx.RotateAt(Rotation, New PointF(CSng(rect.Height * Math.Sin(Rotation / 57.3)), 0))
                    .Transform = mx
                End Using
    
                .TranslateTransform(CSng(rect.Height * Math.Sin(Rotation / 57.3)), 0)
                .FillRectangle(New SolidBrush(Color.SkyBlue), rect)
                .DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), 0, 0)
    
                .EndContainer(gContainer)
            End With
        End Sub
    End Class
    


    2015年10月11日 0:50
  • PS So once its a control added to the form it gets the benefits of being a control. The background is automatically painted control.backcolor etc. The control can be created and edited from the toolbar like a control.

    I just want to turn off the things drawn automatically by the system for the control and only draw my own, like the background. And if there is a property like backgroundimage and the user assigns it to the control I just want it ignored unless I draw it in the class on paint I guess.

    In my first example, when I was not adding as a control and drawing to the form graphics surface, the background was not drawn automatically by the system as it is was still a class only, I guess.

    I seem to recall being shown that you can just set e.handled = true or similar in some paint event [to cancel all drawing by the system for the control]?? But it may have been a datagridview or something different.



    2015年10月11日 1:26
  • "....and will have the same problem that IronRazerz has ...."

     Yes, that could be seen as a problem but,  normally you would resize the Labels and place them next to another control,  not over top of each other.  I suppose i could add code to make it truly transparent when the backcolor is set to Transparent but, unless CalebJohnny wants to use it and says it is a problem, i will leave it how it is.

     There are some things i can see that could be a problem with doing it the way you did too, such as you can not see what they look like or if you have them in the right locations.  So in some situations you would have to adjust the location,  run the app,  stop the app, adjust the location, run the app,  stop the app, ....... until you get each one placed correctly.

     If you had Labels in different container controls,  you would have to add code to each of their Paint events in the Form`s code to handle the Labels that are in each one.

     Another is,  it does not have the options of a Control Object so, you could not change it`s Parent if needed,  use the mouse events to move it or catch a click or double click without adding more code to the form`s code to do it,  find it in a control collection,  change its z order (BringToFront/SendToBack),  and on and on....

     So,  i guess it depends on the way the user intends to use the labels that determines weather or not any of these things are seen as problems.   8)


    If you say it can`t be done then i`ll try it

    2015年10月11日 2:22
  • If you want to achieve the layout you showed in your first post (now amended) you will need to set the region - this should be done in the inherited class.

    The following shows one way of achieving it - it needs a lot more work to make it fully useable, i.e. handle differing text alignments, handle rotation  more than 90 etc.

    Public Class myLabel
       Inherits Control
       Private TextRectangle As Rectangle
       Private Mtx As Matrix
       Private gp As GraphicsPath
       Private _TextRotation As Single = 45
       Public Property TextRotation As Single
          Get
             Return _TextRotation
          End Get
          Set(value As Single)
             _TextRotation = value Mod 360
             SetRegion(Nothing, Nothing)
          End Set
       End Property
       Public Overrides Property Text As String
          Get
             Return MyBase.Text
          End Get
          Set(value As String)
             MyBase.Text = value
             Dim TextSize As Size = TextRenderer.MeasureText(value, Font)
             TextRectangle = New Rectangle(New Point(0, 0), TextSize)
          End Set
       End Property
       Public Sub New()
          TextRectangle = New Rectangle(0, 0, Width, Height)
          Region = New Region
       End Sub
       Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
          e.Graphics.Transform = Mtx
          Using Brsh As New SolidBrush(ForeColor)
             e.Graphics.DrawString(Text, Font, Brsh, TextRectangle.Location)
          End Using
       End Sub
       Private Sub SetRegion(sender As Object, e As EventArgs) Handles Me.Resize, Me.TextChanged, Me.FontChanged
          If Mtx IsNot Nothing Then Mtx.Dispose()
          Mtx = New Matrix
          If gp IsNot Nothing Then gp.Dispose()
          gp = New GraphicsPath
          gp.AddRectangle(TextRectangle)
          Mtx.Translate(CInt(TextRectangle.Height * Math.Sin(TextRotation / (180 / Math.PI))), 0)
          Mtx.Rotate(TextRotation)
          gp.Transform(Mtx)
          If Region IsNot Nothing Then Region.Dispose()
          Region = New Region(gp)
       End Sub
    End Class

    Using this you can produce something like the following where all the labels are controls:



    • 已编辑 Dave299 2015年10月11日 17:17
    2015年10月11日 17:14
  • Ok then. For now I am convinced. Or at least exhausted. Seems using a region is the only way to mask the drawing background in a label. Well maybe using transparent would work?.

    Although it seems like there is a way to turn off the system drawing the background and text but I cant find it again. And the e.handled seems to only be available in the keypress and mousedown.

    So I did one a region in the paint event of a normal label.

    Guess we beat that enough, for now...

    Option Strict On
    Imports System.Drawing.Drawing2D
    
    Public Class Form3
        Private WithEvents Label1 As New Label With {.Location = New Point(50, 50), .Size = New Size(120, 120), .Font = New Font("Arial", 24, FontStyle.Bold), .Text = "Testing 1", .ForeColor = Color.Red, .BackColor = Color.White, .Tag = 45}
        Private WithEvents Label2 As New Label With {.Location = New Point(100, 50), .Size = New Size(120, 120), .Font = New Font("Arial", 24, FontStyle.Bold), .Text = "Testing 2", .ForeColor = Color.Green, .BackColor = Color.White, .Tag = 25}
        Private WithEvents Label3 As New Label With {.Location = New Point(150, 50), .Size = New Size(120, 120), .Font = New Font("Arial", 24, FontStyle.Bold), .Text = "Testing 3", .ForeColor = Color.Blue, .BackColor = Color.White, .Tag = 0}
    
        Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Controls.Add(Label1)
            Controls.Add(Label2)
            Controls.Add(Label3)
        End Sub
    
        Private Sub Label1_Paint(sender As Object, e As PaintEventArgs) Handles Label1.Paint, Label2.Paint, Label3.Paint
            Dim theLabel As Label = CType(sender, Label)
    
            Using textPath As New GraphicsPath, _
                rectPath As New GraphicsPath, _
                mx As New Matrix
    
                textPath.AddString(theLabel.Text, theLabel.Font.FontFamily, theLabel.Font.Style, theLabel.Font.Size, New Point(0, 0), StringFormat.GenericDefault)
    
                Dim rect As RectangleF = textPath.GetBounds
                rect.Inflate(New Size(5, 5))
                rectPath.AddRectangle(rect)
    
                mx.Translate(CSng(rect.Height * Math.Sin(CSng(theLabel.Tag) / 57.3)), 0)
                mx.RotateAt(CSng(theLabel.Tag), New Point(0, 0))
                textPath.Transform(mx)
                rectPath.Transform(mx)
    
                Using r As New Region(rectPath)
                    theLabel.Region = r
                    e.Graphics.FillPath(New SolidBrush(theLabel.BackColor), rectPath)
                    e.Graphics.DrawPath(New Pen(theLabel.ForeColor, 2), rectPath)
                    e.Graphics.FillPath(New SolidBrush(theLabel.ForeColor), textPath)
                End Using
            End Using
        End Sub
    End Class
    
    

    2015年10月11日 23:02
  • Seems using a region is the only way to mask the drawing background in a label. Well maybe using transparent would work?.

    No it won't.  Setting a control's background to transparent doesn't make it transparent - it simply tells it to display its parent's background.  If you put a label with a transparent background on top of another control you won't be able to see the other control, only the forms background.  You can see this more clearly if you set a background image for the form.

    Although it seems like there is a way to turn off the system drawing the background and text but I cant find it again.

    If you inherit from the control you can disable the background drawing by overriding the OnPaintBackground method.  That won't stop the border (if set) being drawn though, which is why I suggested inheriting from Control rather than from Label.




    2015年10月12日 0:16
  • I know this solution was posted 3 years ago, but I just tried implementing IronRazerz "myLabel' class and ran into a problem I'm hoping you can help me with. 

    Your class worked 'perfectly' for my needs right up until I tried to use it with a non-square label.

    I rotated the text 270 degree then reduced the width to less than the size that the text would be at 0 degrees. As I did so, the text began to erase! (Just like it would do if it was at 0 degrees).

    Any ideas on how to stop this behavior or is it part of the control's 'features'?

    2018年10月12日 14:57
  • Thanks!  That's a neat little class there.  Wish I'd thought of that.  Works a treat!
    2018年12月1日 16:52
  • Not sure if you will respond since 6+ years have gone by, but...

    I can't size the control properly to the size I want when I have the text angle set to 270.

    The control sizes as if the text angle is still 0. And ideas on how to resolve that? Thanks

    2020年12月5日 3:31