Rotate and transform the text with stringformat
-
Tuesday, October 18, 2011 7:23 AM
I want to Rotate the text with given degree and ALSO WANT TO PLACE THIS ROTATED TEXT WITH ALL THE STRING ALIGNMENTS.
I can rotate the text using "RotateTransform" and "TranslateTransform". If I am selecting the STRING ALIGNMENT as BOTTOM LEFT, the text is not seen in the control's boundary. Can anyone please help me to get the rectangle if the Rotation angle is changed so that the text will be properly fit in the controls's boundary.
All Replies
-
Tuesday, October 18, 2011 7:27 AM
??
Rotate text? What is that suppose to mean Exactly?
Show us an example how it should look like.
Mitja -
Tuesday, October 18, 2011 7:30 AM
-
Tuesday, October 18, 2011 7:30 AM
Are you like Mitja asked to show what you mean, the best way would be in an image.
You can paste in images into this forum if you use this button when you are in edit mode.

Success
Cor -
Tuesday, October 18, 2011 9:01 AM
- Edited by Amolpbhavsar Tuesday, October 18, 2011 9:05 AM
- Edited by Amolpbhavsar Tuesday, October 18, 2011 9:05 AM
-
Tuesday, October 18, 2011 10:55 AM
...
I can rotate the text using "RotateTransform" and "TranslateTransform". If I am selecting the STRING ALIGNMENT as BOTTOM LEFT, the text is not seen in the control's boundary. Can anyone please help me to get the rectangle if the Rotation angle is changed so that the text will be properly fit in the controls's boundary.
Hi,what language?
could you provide some code where it does not work? Where do you rotate your graphics-context? At its center? At its origin? do you observe the bigger size needed when rotating (esp: at the center)? ...
Regards,
Thorsten
- Edited by Thorsten GuderaMicrosoft Community Contributor Tuesday, October 18, 2011 10:58 AM
-
Tuesday, October 18, 2011 11:20 AM
Im am following the code given in above codeproject link. The rotated text can be drawn properly. but if I want to draw this rotated text in CENTER - LEFT position using string alignment, it is not drawn properly. In fact it is going out of the boundary of the control. I want to draw this rotated text in all of the string alignment position. (Top left, top center, top right, center left, center middle, center right, bottom left, bottom center, bottom right), The example shows only draw the text at one location.
-
Tuesday, October 18, 2011 12:04 PM
For these, you'll have to rotate the graphics-context at different locations. Not always width / 2, height / 2 -> which is the center point, but for instance af textstart (0) and height / 2 for left(x) center(y), I think.
Regards,
Thorsten
-
Tuesday, October 18, 2011 12:14 PM
... something like this:
(I only implemented the logic for MiddleLeft MiddleMiddle and MiddleRight for use with the TextAlign-Property)
public class MyLabel : Label { private float _rotation = 0F; public float Rotation { get { return _rotation; } set { _rotation = value; CheckSize(); this.Invalidate(); } } public MyLabel() { this.SetStyle(ControlStyles.UserPaint, true); this.AutoSize = false; //this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; } private void CheckSize() { SizeF sz; using (Graphics g = this.CreateGraphics()) sz = g.MeasureString(this.Text, this.Font); RectangleF r = new RectangleF(0, 0, sz.Width, sz.Height); using (System.Drawing.Drawing2D.GraphicsPath gPath = new System.Drawing.Drawing2D.GraphicsPath()) { gPath.AddRectangle(r); double rot = _rotation / 180.0 * Math.PI; gPath.Transform(new System.Drawing.Drawing2D.Matrix((float)Math.Cos(rot), -(float)Math.Sin(rot), (float)Math.Sin(rot), (float)Math.Cos(rot), 0, 0)); RectangleF rr = gPath.GetBounds(); if (this.ClientSize.Width < rr.Width) { this.ClientSize = new Size((int)Math.Ceiling(rr.Width), this.ClientSize.Height); } if (this.ClientSize.Height < rr.Height) { this.ClientSize = new Size(this.ClientSize.Width, (int)Math.Ceiling(rr.Height)); } } } protected override void OnPaint(PaintEventArgs e) { this.AutoSize = false; System.Drawing.Drawing2D.GraphicsContainer con = e.Graphics.BeginContainer(); float xAdd = 0; float yAdd = 0; SizeF sz = e.Graphics.MeasureString(this.Text, this.Font); //only cl,cc,cr implemented switch (this.TextAlign) { case ContentAlignment.MiddleLeft: xAdd = (this.ClientSize.Width / 2F) - sz.Width / 2f; break; case ContentAlignment.MiddleRight: xAdd = -((this.ClientSize.Width / 2F) - sz.Width / 2f); break; } if (this.Rotation != 0f) { System.Drawing.Drawing2D.Matrix mx = e.Graphics.Transform; mx.RotateAt(this.Rotation, new PointF(this.ClientSize.Width / 2F - xAdd, this.ClientSize.Height / 2F - yAdd), System.Drawing.Drawing2D.MatrixOrder.Append); e.Graphics.Transform = mx; } e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; using (SolidBrush sb = new SolidBrush(this.ForeColor)) e.Graphics.DrawString(this.Text, this.Font, sb, new PointF((this.ClientSize.Width - sz.Width) / 2F - xAdd, (this.ClientSize.Height - sz.Height) / 2F - yAdd)); e.Graphics.EndContainer(con); } protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); CheckSize(); this.Invalidate(); } }
Regards,Thorsten
- Edited by Thorsten GuderaMicrosoft Community Contributor Tuesday, October 18, 2011 12:15 PM
- Proposed As Answer by Neddy RenModerator Thursday, October 20, 2011 8:02 AM
- Marked As Answer by Neddy RenModerator Thursday, October 27, 2011 2:38 AM
-
Tuesday, October 18, 2011 12:18 PM
The LayoutRectangle passed to the DrawString method is also rotated. If you always want to rotate at the center of the text and also want to specify an alignment, it is getting more complicated, and you'll have to do some calculations on your own. That might involve some trigonometrie.
Have a look at the following illustration showing a top-left aligned text.
- The black rectangle is the containg control.
- The red rectangle is the rotated surrounding rectangle of the String.
- The green rectangle is the unrotated surrounding rectangle of the String.Version A: The Text always touches the borders of the containing control.
Version B: The Text' center is always the center of the green rectangle. The width and height of the green rectangle is equal to the length of the diagonal of the red rectangle.With both versions you will have to rotate the Text at it's center and also apply a transformation matrix. The difference between the versions is the calculation of the rotation center. Version A is more complicated to calculate.
So, if I understood your concerns correctly, which version is your favorite?
Armin- Edited by Armin Zingler Tuesday, October 18, 2011 12:20 PM
-
Tuesday, October 18, 2011 1:04 PM
Thanks for the reply
Can you suggest the remaining calculation for the text alignment?
Any hint please?
-
Tuesday, October 18, 2011 1:39 PM
I have made the code
switch (this.TextAlign)
{
case ContentAlignment.MiddleLeft:
xAdd = (this.ClientSize.Width / 2F) - sz.Width / 2f;
break;
case ContentAlignment.MiddleRight:
xAdd = -((this.ClientSize.Width / 2F) - sz.Width / 2f);
break;
case ContentAlignment.TopCenter:
yAdd = (this.ClientSize.Height / 2F) - sz.Height * 2F ;
break;
case ContentAlignment.TopLeft:
xAdd = (this.ClientSize.Width / 2F) - sz.Width / 2f;
yAdd = (this.ClientSize.Height / 2F) - sz.Height * 2F;
break;
case ContentAlignment.TopRight:
xAdd = -((this.ClientSize.Width / 2F) - sz.Width / 2f);
yAdd = (this.ClientSize.Height / 2F) - sz.Height * 2F;
break;
case ContentAlignment.BottomLeft :
xAdd = (this.ClientSize.Width / 2F) - sz.Width / 2f;
yAdd = -((this.ClientSize.Height / 2F) - (sz.Height * 2F));
break;
case ContentAlignment.BottomRight:
xAdd = -((this.ClientSize.Width / 2F) - sz.Width / 2f);
yAdd = -((this.ClientSize.Height / 2F) - (sz.Height * 2F));
break;
case ContentAlignment.BottomCenter :
yAdd = -((this.ClientSize.Height / 2F) - (sz.Height * 2F));
break;
}
Is this code is correct?
- Edited by Amolpbhavsar Tuesday, October 18, 2011 1:58 PM
-
Tuesday, October 18, 2011 2:04 PM
Hi,
I think, yes, it is alright. The code is correct when the results are correct.
Regards,
Thorsten
-
Wednesday, October 19, 2011 4:44 AMSometimes text gets cut when a long string is set as text even though the control size is enough bigger then the size of the text. Can you please look in to it?
-
Wednesday, October 19, 2011 11:31 AM
Hi,
could you give an example? I used Text = "this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;";
Regards,
Thorsten
-
Wednesday, October 19, 2011 12:10 PM
... ok, i see now. ThereÄ's two things to do:
First, your calculation isnt right sz.Height * 2F should be sz.Height / 2F in the switch
Second, you'll have to do some verifying that the rotation and drawing of the string is in a range from 0 to label.clientsize.width - the surrounding rect of the rotated string width. Same for height.
I do not have the time to do this right now. Maybe tomorrow.
Regards,
Thorsten
-
Wednesday, October 19, 2011 1:08 PM
... I did play around with it a bit, here's the new paint-method:
protected override void OnPaint(PaintEventArgs e) { this.AutoSize = false; System.Drawing.Drawing2D.GraphicsContainer con = e.Graphics.BeginContainer(); float xAdd = 0; float yAdd = 0; double rot = _rotation / 180.0 * Math.PI; SizeF sz = e.Graphics.MeasureString(this.Text, this.Font); RectangleF rr = new RectangleF(0, 0, sz.Width, sz.Height); RectangleF r = new RectangleF(0, 0, sz.Width, sz.Height); using (System.Drawing.Drawing2D.GraphicsPath gPath = new System.Drawing.Drawing2D.GraphicsPath()) { gPath.AddRectangle(r); gPath.Transform(new System.Drawing.Drawing2D.Matrix((float)Math.Cos(rot), -(float)Math.Sin(rot), (float)Math.Sin(rot), (float)Math.Cos(rot), 0, 0)); rr = gPath.GetBounds(); } switch (this.TextAlign) { case ContentAlignment.MiddleLeft: xAdd = (this.ClientSize.Width - rr.Width) / 2F; break; case ContentAlignment.MiddleRight: xAdd = -(this.ClientSize.Width - rr.Width) / 2F; break; case ContentAlignment.TopCenter: yAdd = (this.ClientSize.Height - rr.Height) / 2F; break; case ContentAlignment.TopLeft: xAdd = (this.ClientSize.Width - rr.Width) / 2F; yAdd = (this.ClientSize.Height - rr.Height) / 2F; break; case ContentAlignment.TopRight: xAdd = -(this.ClientSize.Width - rr.Width) / 2F; yAdd = (this.ClientSize.Height - rr.Height) / 2F; break; case ContentAlignment.BottomLeft: xAdd = (this.ClientSize.Width - rr.Width) / 2f; yAdd = -(this.ClientSize.Height - rr.Height) / 2F; break; case ContentAlignment.BottomRight: xAdd = -(this.ClientSize.Width - rr.Width) / 2f; yAdd = -(this.ClientSize.Height - rr.Height) / 2F; break; case ContentAlignment.BottomCenter: yAdd = -(this.ClientSize.Height - rr.Height) / 2F; break; } e.Graphics.TranslateTransform( (-xAdd * (float)Math.Cos(rot)) + (-yAdd * (float)Math.Sin(rot)), -(-xAdd * (float)Math.Sin(rot)) + (-yAdd * (float)Math.Cos(rot)), System.Drawing.Drawing2D.MatrixOrder.Append); if (this.Rotation != 0f) { System.Drawing.Drawing2D.Matrix mx = e.Graphics.Transform; mx.RotateAt(this.Rotation, new PointF((this.ClientSize.Width / 2F), this.ClientSize.Height / 2F), System.Drawing.Drawing2D.MatrixOrder.Append); e.Graphics.Transform = mx; } e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; using (SolidBrush sb = new SolidBrush(this.ForeColor)) { e.Graphics.DrawString(this.Text, this.Font, sb, new PointF((this.ClientSize.Width - sz.Width) / 2F, (this.ClientSize.Height - sz.Height) / 2F)); } e.Graphics.EndContainer(con); }
Regards,Thorsten
- Proposed As Answer by Neddy RenModerator Thursday, October 20, 2011 8:00 AM
- Marked As Answer by Neddy RenModerator Thursday, October 27, 2011 2:38 AM
-
Wednesday, October 19, 2011 1:42 PM
If I may jump in...
As you may have seen below, I was also trying to provide a solution. I didn't post mine because of Thorsten's great efforts, so I wanted to wait how things develop. However, if you may want to have a look at my approach...:
Sorry, it's VB code, but I think you get the point:
The question from my first message in the thread which alignment strategy you prefer still remains, but both could be implemented easily now.Class MyLabel Inherits Label Private f_Rotation As Double 'in degrees Private f_TextSize As SizeF Private f_EnclosingRectangleSize As SizeF Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) Using b As New SolidBrush(ForeColor) Dim ControlCenter As PointF Dim TextCenter As PointF ControlCenter.X = ClientSize.Width / 2.0F ControlCenter.Y = ClientSize.Height / 2.0F Select Case TextAlign Case ContentAlignment.BottomCenter, ContentAlignment.MiddleCenter, ContentAlignment.TopCenter TextCenter.X = ControlCenter.X Case ContentAlignment.BottomLeft, ContentAlignment.MiddleLeft, ContentAlignment.TopLeft TextCenter.X = f_EnclosingRectangleSize.Width / 2 Case ContentAlignment.BottomRight, ContentAlignment.MiddleRight, ContentAlignment.TopRight TextCenter.X = ClientSize.Width - f_EnclosingRectangleSize.Width / 2 End Select Select Case TextAlign Case ContentAlignment.BottomCenter, ContentAlignment.BottomLeft, ContentAlignment.BottomRight TextCenter.Y = ClientSize.Height - f_EnclosingRectangleSize.Height / 2 Case ContentAlignment.MiddleCenter, ContentAlignment.MiddleLeft, ContentAlignment.MiddleRight TextCenter.Y = ControlCenter.Y Case ContentAlignment.TopCenter, ContentAlignment.TopLeft, ContentAlignment.TopRight TextCenter.Y = f_EnclosingRectangleSize.Height / 2 End Select e.Graphics.TranslateTransform(TextCenter.X, TextCenter.Y) e.Graphics.RotateTransform(CSng(f_Rotation)) e.Graphics.DrawString(Text, Font, Brushes.White, -f_TextSize.Width / 2, -f_TextSize.Height / 2) End Using End Sub Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs) MyBase.OnTextChanged(e) UpdateTextSize() End Sub Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs) MyBase.OnFontChanged(e) UpdateTextSize() End Sub Public Property Rotation() As Double Get Return f_Rotation End Get Set(ByVal value As Double) If f_Rotation = value Then Return f_Rotation = value UpdateEnclosingRectangleSize() Invalidate() End Set End Property Private Sub UpdateTextSize() Using g = CreateGraphics() f_TextSize = g.MeasureString(Text, Font) End Using UpdateEnclosingRectangleSize() End Sub Private Sub UpdateEnclosingRectangleSize() f_EnclosingRectangleSize = GetEnclosingRectangleSize(f_TextSize, f_Rotation) End Sub Private Shared Function GetEnclosingRectangleSize(ByVal TextSize As SizeF, ByVal Angle As Double) As SizeF Dim AngleDeg = Angle * DEG Dim Corner1, Corner2 As PointF Dim result As SizeF Corner1.X = TextSize.Width / 2 Corner1.Y = TextSize.Height / 2 Corner2.X = TextSize.Width / 2 Corner2.Y = TextSize.Height / -2 Corner1 = RotatePoint(Corner1, Angle) Corner2 = RotatePoint(Corner2, Angle) result.Width = 2 * (Math.Max(Math.Abs(Corner1.X), Math.Abs(Corner2.X))) result.Height = 2 * (Math.Max(Math.Abs(Corner1.Y), Math.Abs(Corner2.Y))) Return result End Function Private Shared Function RotatePoint(ByVal Point As PointF, ByVal Angle As Double) As PointF Dim AngleDeg = Angle * DEG RotatePoint.X = CSng(Point.X * Math.Cos(AngleDeg) - Point.Y * Math.Sin(AngleDeg)) RotatePoint.Y = CSng(Point.X * Math.Sin(AngleDeg) + Point.Y * Math.Cos(AngleDeg)) End Function End Class
Armin -
Wednesday, October 19, 2011 1:46 PM
Of course, text shouldn't be White always. ;-) Correction:
Using fBrush As New SolidBrush(ForeColor) e.Graphics.DrawString(Text, Font, fBrush, -f_TextSize.Width / 2, -f_TextSize.Height / 2) End Using
Armin -
Wednesday, October 19, 2011 2:16 PM
Hi Armin,
always do it and "jump in". I think, the more ideas shared, the more ways of solving presented, the better the overall solution will be.
Regards,
Thorsten


