Inherited Label with transparency and text rotation

VorTechS

Member
Joined
Oct 19, 2006
Messages
12
Programming Experience
10+
I'm having a problem with an inherited label, applying text rotation to
aligned text.
If text rotation is applied to the aligned text, the alignment goes 'nuts'.
I can find no logic to what is happening.

I've built the following code from several examples, if you
move the Drawstring before the rotation then alignment works fine (but you don't get rotation, unsurprisingly enough):

VB.NET:
Imports System.ComponentModel 
 
Public Class TransparentLabel 
Inherits Label 
 
Private _RotationAngle As Integer 
 
#Region " Windows Form Designer generated code " 
 
Public Sub New() 
MyBase.New() 
 
'This call is required by the Windows Form Designer. 
InitializeComponent() 
 
'Add any initialization after the InitializeComponent() call 
 
End Sub 
 
'UserControl1 overrides dispose to clean up the component list. 
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) 
If disposing Then 
If Not (components Is Nothing) Then 
components.Dispose() 
End If 
End If 
MyBase.Dispose(disposing) 
End Sub 
 
'Required by the Windows Form Designer 
Private components As System.ComponentModel.IContainer 
 
'NOTE: The following procedure is required by the Windows Form Designer 
'It can be modified using the Windows Form Designer. 
'Do not modify it using the code editor. 
<System.Diagnostics.DebuggerStepThrough()> Private Sub 
InitializeComponent() 
' 
'TransparentLabel 
' 
Me.BackColor = System.Drawing.Color.DeepPink 
Me.Name = "TransparentLabel" 
Me.Size = New System.Drawing.Size(256, 46) 
 
End Sub 
 
#End Region 
Public Property RotationAngle() As Integer 
Get 
RotationAngle = _RotationAngle 
End Get 
Set(ByVal value As Integer) 
_RotationAngle = value 
Me.Invalidate() 
End Set 
End Property 
 
Private Sub TransparentLabel_Paint(ByVal sender As Object, ByVal e As 
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint 
Try 
Dim sFormat As StringFormat = Nothing 
 
sFormat = New StringFormat 
 
If Me.TextAlign <= ContentAlignment.TopRight Then 
sFormat.LineAlignment = StringAlignment.Near 
ElseIf Me.TextAlign >= ContentAlignment.BottomRight Then 
sFormat.LineAlignment = StringAlignment.Far 
Else 
sFormat.LineAlignment = StringAlignment.Center 
End If 
 
If Me.TextAlign = ContentAlignment.BottomLeft Or Me.TextAlign = 
ContentAlignment.MiddleLeft Or Me.TextAlign = ContentAlignment.TopLeft Then 
sFormat.Alignment = StringAlignment.Near 
ElseIf Me.TextAlign = ContentAlignment.BottomRight Or 
Me.TextAlign = ContentAlignment.MiddleRight Or Me.TextAlign = 
ContentAlignment.TopRight Then 
sFormat.Alignment = StringAlignment.Far 
Else 
sFormat.Alignment = StringAlignment.Center 
End If 
 
'variables to capture the size of the text area 
Dim width As Double = e.Graphics.MeasureString(Text, 
Me.Font).Width 
Dim height As Double = e.Graphics.MeasureString(Text, 
Me.Font).Height 
'convert the rotation angle into radians for trig functions 
Dim angleRadian As Double = ((_rotationAngle Mod 360) / 180) * 
Math.PI 
'capture the forground color as a brush 
Dim myBrush As Brush = New SolidBrush(Me.ForeColor) 
 
'If Me.BackColor = Color.Transparent Then 
If Me.AutoSize Then 
Dim Siz As Drawing.SizeF = e.Graphics.MeasureString(Me.Text, 
Font) 
Me.Width = Siz.Width + 1 
Me.Height = Siz.Height + 1 
End If 
 
 
Dim B As New Bitmap(Me.Width, Me.Height) 
Dim G As Graphics = Graphics.FromImage(B) 
Dim TextArea As New Rectangle(0, 0, Me.Width, Me.Height) 
 
If Me.BackColor = Color.Transparent Then 
G.FillRectangle(New SolidBrush(Color.DeepPink), TextArea) 
Else 
G.FillRectangle(New SolidBrush(Me.BackColor), TextArea) 
End If 
 
G.TranslateTransform(CInt((ClientRectangle.Width + (height * 
Math.Sin(angleRadian)) - (width * Math.Cos(angleRadian))) / 2), 
CInt((ClientRectangle.Height - (height * Math.Cos(angleRadian)) - (width * 
Math.Sin(angleRadian))) / 2)) 
G.RotateTransform(CInt(_RotationAngle)) 
G.DrawString(Me.Text, Font, myBrush, TextArea, sFormat) 
G.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias 
G.ResetTransform() 
 
Dim Pth As New Drawing2D.GraphicsPath() 
Dim X, Y As Short 
For X = 0 To Me.Width - 1 
For Y = 0 To Me.Height - 1 
If B.GetPixel(X, Y).ToArgb.ToString = 
Color.DeepPink.ToArgb.ToString Then 
Pth.AddRectangle(New Rectangle(X, Y, 1, 1)) 
End If 
Next 
Next 
 
Dim Rgn As Region 
 
If Me.BackColor = Color.Transparent Then 
G.FillRectangle(New SolidBrush(Me.ForeColor), New 
Rectangle(0, 0, Me.Width, Me.Height)) 
End If 
 
e.Graphics.DrawImage(B, 0, 0) 
Rgn = New Region(New Rectangle(0, 0, Me.Width, Me.Height)) 
If Me.BackColor = Color.Transparent Then 
Rgn.Exclude(Pth) 
End If 
Me.Region = Rgn 
 
B.Dispose() 
G.Dispose() 
Catch ex As Exception 
End Try 
End Sub 
 
Private Sub TransparentLabel_Load(ByVal sender As Object, ByVal e As 
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint 
SetStyle(ControlStyles.AllPaintingInWmPaint, True) 
SetStyle(ControlStyles.DoubleBuffer, True) 
SetStyle(ControlStyles.UserPaint, True) 
End Sub 
End Class

Can anyone advise me what I'm doing wrong to throw the alignment out?

Stuart
 
Sorry, my fault I missed a line out.
The rotation is behaving in the same manner as I've had all along...

If the control is not square, because the rotation is working AFTER the text is painted it may be painted outside of the control. I'd like the text to be rotated first, then placed in the specified alignment.
 
What you need to do is resize the control to the size of the text.

Say your string comes back with a size of

Width 100
Height 50

So you now know that your label needs to be at least 100 in height and 50 in width. So just resize the control to those dimensions. Don't bother with a bitmap or a region.
 
After playing around a bit more last night, I noticed that the new code you gave me yesterday doesn't support complete transparency when the object is laid over another. I think this is why region clipping was being used! :D
 
Really? I can't see any reason why not. You mean to say that the transparency doen't work when your label with it's back color set to transparent doesn't stay transparent when you put it over the top of say a button control? If thats the case then to make this easier, it'd probably be an idea to inherit your class from the base class control instead of label. From what i can see you are only using it to display text so you don't really need the functionality of a label anyway.
 
You mean to say that the transparency doen't work when your label with it's back color set to transparent doesn't stay transparent when you put it over the top of say a button control?

Yes, in particular I was testing by overlaying it on an image. I could have sworn it worked yesterday - but I think I was only testing with a form background.

...it'd probably be an idea to inherit your class from the base class control instead of label.

I do need all the functionality of the label - it's just the standard properties aren't affected in what we are trying to achieve. Well, I say 'aren't', but I've just found that a background image isn't displayed so have just had to write some code to extend and behave like a form background image. But that too is being rotated!

I'm going to play around a little more on the rotation to see if I can make the text rotate and then appear the right way. I was having a conversation with a friend who knows a little on GDI and was suggestion that perhaps what I should be doing is working with multiple rectangles?

Unfortunately all the sample GDI stuff I've seen uses single rectangle. Is it possible to have the text and an image as separate rectangles and rotate them separately in the OnPaint method?

If so, do you know of an example illustrating this?
 
It's totally possible to have the text and image as two separate rectangles. If you consider that you are already using a bitmap. Just create a new bitmap of the desired size for your text. You can use the bitmap.RotateFlip enumeration to adjust it to your needs then just paint it to the screen. Same with the image.
 
Back
Top