How do I rotate a label in C#? [duplicate] - c#

This question already has answers here:
C# vertical label in a Windows Forms
(9 answers)
Closed 9 years ago.
I want to show a label rotated 90 degrees (so I can put a bunch of them at the top of a table as the headings). Is there an easy way to do this?

You will need to write your own or use a custom control.
A The Code Project article you can start with is Customized Text - Orientated Controls in C# - Part I (Label Control). This contains extra functionality, so you should be able to trim it down if you'd like.
And here is some code from it that is of interest:
/// <summary>
/// This is a lable, in which you can set the text in any direction/angle
/// </summary>
#region Orientation
//Orientation of the text
public enum Orientation
{
Circle,
Arc,
Rotate
}
public enum Direction
{
Clockwise,
AntiClockwise
}
#endregion
public class OrientedTextLabel : System.Windows.Forms.Label
{
#region Variables
private double rotationAngle;
private string text;
private Orientation textOrientation;
private Direction textDirection;
#endregion
#region Constructor
public OrientedTextLabel()
{
//Setting the initial condition.
rotationAngle = 0d;
textOrientation = Orientation.Rotate;
this.Size = new Size(105,12);
}
#endregion
#region Properties
[Description("Rotation Angle"),Category("Appearance")]
public double RotationAngle
{
get
{
return rotationAngle;
}
set
{
rotationAngle = value;
this.Invalidate();
}
}
[Description("Kind of Text Orientation"),Category("Appearance")]
public Orientation TextOrientation
{
get
{
return textOrientation;
}
set
{
textOrientation = value;
this.Invalidate();
}
}
[Description("Direction of the Text"),Category("Appearance")]
public Direction TextDirection
{
get
{
return textDirection;
}
set
{
textDirection = value;
this.Invalidate();
}
}
[Description("Display Text"),Category("Appearance")]
public override string Text
{
get
{
return text;
}
set
{
text = value;
this.Invalidate();
}
}
#endregion
#region Method
protected override void OnPaint(PaintEventArgs e)
{
Graphics graphics = e.Graphics;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
Brush textBrush = new SolidBrush(this.ForeColor);
//Getting the width and height of the text, which we are going to write
float width = graphics.MeasureString(text,this.Font).Width;
float height = graphics.MeasureString(text,this.Font).Height;
//The radius is set to 0.9 of the width or height, b'cos not to
//hide and part of the text at any stage
float radius = 0f;
if (ClientRectangle.Width<ClientRectangle.Height)
{
radius = ClientRectangle.Width *0.9f/2;
}
else
{
radius = ClientRectangle.Height *0.9f/2;
}
//Setting the text according to the selection
switch (textOrientation)
{
case Orientation.Arc:
{
//Arc angle must be get from the length of the text.
float arcAngle = (2*width/radius)/text.Length;
if(textDirection == Direction.Clockwise)
{
for (int i=0; i<text.Length; i++)
{
graphics.TranslateTransform(
(float)(radius*(1 - Math.Cos(arcAngle*i + rotationAngle/180 * Math.PI))),
(float)(radius*(1 - Math.Sin(arcAngle*i + rotationAngle/180*Math.PI))));
graphics.RotateTransform((-90 + (float)rotationAngle + 180*arcAngle*i/(float)Math.PI));
graphics.DrawString(text[i].ToString(), this.Font, textBrush, 0, 0);
graphics.ResetTransform();
}
}
else
{
for (int i=0; i<text.Length; i++)
{
graphics.TranslateTransform(
(float)(radius*(1 - Math.Cos(arcAngle*i + rotationAngle/180*Math.PI))),
(float)(radius*(1 + Math.Sin(arcAngle*i + rotationAngle/180*Math.PI))));
graphics.RotateTransform((-90 - (float)rotationAngle - 180*arcAngle*i/(float)Math.PI));
graphics.DrawString(text[i].ToString(), this.Font, textBrush, 0, 0);
graphics.ResetTransform();
}
}
break;
}
case Orientation.Circle:
{
if (textDirection == Direction.Clockwise)
{
for(int i=0;i<text.Length;i++)
{
graphics.TranslateTransform(
(float)(radius*(1 - Math.Cos((2*Math.PI/text.Length)*i + rotationAngle/180*Math.PI))),
(float)(radius*(1 - Math.Sin((2*Math.PI/text.Length)*i + rotationAngle/180*Math.PI))));
graphics.RotateTransform(-90 + (float)rotationAngle + (360/text.Length)*i);
graphics.DrawString(text[i].ToString(), this.Font, textBrush, 0, 0);
graphics.ResetTransform();
}
}
else
{
for(int i=0;i<text.Length;i++)
{
graphics.TranslateTransform(
(float)(radius*(1 - Math.Cos((2*Math.PI/text.Length)*i + rotationAngle/180*Math.PI))),
(float)(radius*(1 + Math.Sin((2*Math.PI/text.Length)*i + rotationAngle/180*Math.PI))));
graphics.RotateTransform(-90 - (float)rotationAngle - (360/text.Length)*i);
graphics.DrawString(text[i].ToString(), this.Font, textBrush, 0, 0);
graphics.ResetTransform();
}
}
break;
}
case Orientation.Rotate:
{
//For rotation, who about rotation?
double angle = (rotationAngle/180)*Math.PI;
graphics.TranslateTransform(
(ClientRectangle.Width+(float)(height*Math.Sin(angle))-(float)(width*Math.Cos(angle)))/2,
(ClientRectangle.Height-(float)(height*Math.Cos(angle))-(float)(width*Math.Sin(angle)))/2);
graphics.RotateTransform((float)rotationAngle);
graphics.DrawString(text,this.Font,textBrush,0,0);
graphics.ResetTransform();
break;
}
}
}
#endregion
}

You can also take a look at the Windows ToolStrip control. It has an option for TextDirection that can be set to Vertical90 or Vertical270 and this will rotate your Label text in the appropriate direction.
Overview: ToolStrip Class (MSDN)
Setting the property (learn.microsoft.com)
Enumerated Values (learn.microsoft.com)

Related

Toolbar badge count is not working when I tried to set it programmatically from ViewModel

I have made dependency services on both side and Interface in shared library on Xamarin platform
when i use it in xaml.cs hard coded it works but when i use it in ViewModel using messaging center to set count of notification in Toolbar of application it doesn't works
Does anyone have any kind of idea whats happening or should i do ?
this code works from Xaml.cs page
DependencyService.Get<IToolbarItemBadgeService>().SetBadge(this, ToolbarItems[0], "2", Color.Red, Color.White);
And Below Code doesn't works
From ViewModel
" MessagingCenter.Send(new MessagingCenterModel { }, "NotificationCount", NotificationListCount);
At Xaml.cs Page
MessagingCenter.Subscribe<MessagingCenterModel, string>(this, "NotificationCount", (sender, args) =>
{
DependencyService.Get<IToolbarItemBadgeService>().SetBadge(this, ToolbarItems[0], args, Color.Red, Color.White);
});
InterFaceCode
public interface IToolbarItemBadgeService
{
void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor);
}
Dependency service
public class ToolbarItemBadgeService : IToolbarItemBadgeService
{
public void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor)
{
Device.BeginInvokeOnMainThread(() =>
{
var toolbar = CrossCurrentActivity.Current.Activity.FindViewById(Resource.Id.toolbar) as Android.Support.V7.Widget.Toolbar;
if (toolbar != null)
{
if (!string.IsNullOrEmpty(value))
{
var idx = page.ToolbarItems.IndexOf(item);
if (toolbar.Menu.Size() > idx)
{
var menuItem = toolbar.Menu.GetItem(idx);
BadgeDrawable.SetBadgeText(CrossCurrentActivity.Current.Activity, menuItem, value, backgroundColor.ToAndroid(), textColor.ToAndroid());
}
}
}
});
}
}
BadgeDrawable Class
public class BadgeDrawable : Drawable
{
private const string BadgeValueOverflow = "*";
private Paint _badgeBackground;
private Paint _badgeText;
private Rect _textRect = new Rect();
private string _badgeValue = "";
private bool _shouldDraw = true;
Context _context;
public override int Opacity => (int)Format.Unknown;
public BadgeDrawable(Context context, Color backgroundColor, Color textColor)
{
_context = context;
float textSize = context.Resources.GetDimension(Resource.Dimension.textsize_badge_count);
_badgeBackground = new Paint();
_badgeBackground.Color = backgroundColor;
_badgeBackground.AntiAlias = true;
_badgeBackground.SetStyle(Paint.Style.Fill);
_badgeText = new Paint();
_badgeText.Color = textColor;
_badgeText.SetTypeface(Typeface.Default);
_badgeText.TextSize = textSize;
_badgeText.AntiAlias = true;
_badgeText.TextAlign = Paint.Align.Center;
}
public override void Draw(Canvas canvas)
{
if (!_shouldDraw)
{
return;
}
Rect bounds = Bounds;
float width = bounds.Right - bounds.Left;
float height = bounds.Bottom - bounds.Top;
float oneDp = 1 * _context.Resources.DisplayMetrics.Density;
// Position the badge in the top-right quadrant of the icon.
float radius = ((Java.Lang.Math.Max(width, height) / 2)) / 2;
float centerX = (width - radius - 1) + oneDp * 2;
float centerY = radius - 2 * oneDp;
canvas.DrawCircle(centerX, centerY, (int)(radius + oneDp * 5), _badgeBackground);
// Draw badge count message inside the circle.
_badgeText.GetTextBounds(_badgeValue, 0, _badgeValue.Length, _textRect);
float textHeight = _textRect.Bottom - _textRect.Top;
float textY = centerY + (textHeight / 2f);
canvas.DrawText(_badgeValue.Length > 2 ? BadgeValueOverflow : _badgeValue,
centerX, textY, _badgeText);
}
// Sets the text to display. Badge displays a '*' if more than 2 characters
private void SetBadgeText(string text)
{
_badgeValue = text;
// Only draw a badge if the value isn't a zero
_shouldDraw = !text.Equals("0");
InvalidateSelf();
}
public override void SetAlpha(int alpha)
{
// do nothing
}
public override void SetColorFilter(ColorFilter cf)
{
// do nothing
}
public static void SetBadgeCount(Context context, IMenuItem item, int count, Color backgroundColor, Color textColor)
{
SetBadgeText(context, item, $"{count}", backgroundColor, textColor);
}
public static void SetBadgeText(Context context, IMenuItem item, string text, Color backgroundColor, Color textColor)
{
if (item.Icon == null)
{
return;
}
BadgeDrawable badge = null;
Drawable icon = item.Icon;
if (item.Icon is LayerDrawable)
{
LayerDrawable lDrawable = item.Icon as LayerDrawable;
if (string.IsNullOrEmpty(text) || text == "0")
{
icon = lDrawable.GetDrawable(0);
lDrawable.Dispose();
}
else
{
for (var i = 0; i < lDrawable.NumberOfLayers; i++)
{
if (lDrawable.GetDrawable(i) is BadgeDrawable)
{
badge = lDrawable.GetDrawable(i) as BadgeDrawable;
break;
}
}
if (badge == null)
{
badge = new BadgeDrawable(context, backgroundColor, textColor);
icon = new LayerDrawable(new Drawable[] { item.Icon, badge });
}
}
}
else
{
badge = new BadgeDrawable(context, backgroundColor, textColor);
icon = new LayerDrawable(new Drawable[] { item.Icon, badge });
}
badge?.SetBadgeText(text);
item.SetIcon(icon);
icon.Dispose();
}
}
Firstly , make sure that we had Subscribe the message before we send it . Otherwise the codes in Subscribe will never been called .
In addition , the code in Dependency Service could only set the badge of ToolbarItem in the navigation bar (on tabbed bar it will never work).
If you want to set the badge of tabbed page icon , you could use the plugin Plugin.Badge .

DrawArc is Coming up Short

I am having a small issue with using Graphics.DrawArc method. When used it's coming up short than what the actual size is. I am basing this control off another post found here
I am trying to make this into a UserControl with some properties and expand on it. The issue is when I set the percentage per say 50% it comes up short...
This is what the UserControl looks like at 50%... It's should be centered (blue) at the bottom of circle. I have tried adjusting everything I could, but I am at lost right now.
Here is my current code...
Color _ProgressCompletedColor = SystemColors.MenuHighlight;
Color _ProgressNotCompleted = Color.LightGray;
Int32 _ProgressThickness = 2;
Single _ProgressCompleted = 25;
public AttuneProgressBar()
{
InitializeComponent();
}
public Single PercentageCompleted
{
get
{
return this._ProgressCompleted;
}
set
{
this._ProgressCompleted = value;
this.Invalidate();
}
}
public Int32 ProgressBarThickness
{
get
{
return this._ProgressThickness;
}
set
{
this._ProgressThickness = value;
this.Invalidate();
}
}
public Color ProgressNotCompletedColor
{
get
{
return this._ProgressNotCompleted;
}
set
{
this._ProgressNotCompleted = value;
this.Invalidate();
}
}
public Color ProgressCompletedColor
{
get
{
return this._ProgressCompletedColor;
}
set
{
this._ProgressCompletedColor = value;
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
// Call the OnPaint method of the base class.
base.OnPaint(e);
DrawProgress(e.Graphics, new Rectangle(new Point(1,1), new Size(this.ClientSize.Width - 3, this.ClientSize.Height - 3)), PercentageCompleted);
}
private void DrawProgress(Graphics g, Rectangle rec, Single percentage)
{
Single progressAngle = (360 / 100 * percentage);
Single remainderAngle = 360 - progressAngle;
try
{
using (Pen progressPen = new Pen(ProgressCompletedColor, ProgressBarThickness), remainderPen = new Pen(ProgressNotCompletedColor, ProgressBarThickness))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.DrawArc(progressPen, rec, -90, progressAngle);
g.DrawArc(remainderPen, rec, progressAngle - 90, remainderAngle);
}
}
catch (Exception exc) { }
}
}
You are calculating the angle with integers. When you do this:
angle = 360 / 100 * percentage;
it means
angle = 3 * percentage;
this of course leads to errors. There is a simple fix if you want to keep using ints:
angle = 360 * percentage / 100;
This way it doesn't get rounded down before multiplication. Or you can just use floats all the way:
angle = 360f / 100f * percentage;

How would i make a circular graph in c#?

hello I am making an application that the design requires special graphs that change depending on the value that is give. like this:
how would i go about doing this? could someone point me in the right direction?
the outer ring of the orange changes with the value but the middle circle stays static.
p.s my paint skills are amazing.
You can draw your own control quite easily. The main thing is the FillPie method, which draws only part of a circle. To change the starting point of the outer ring or the filling direction you need to change the starting and sweep angle in the FillPie call of the OnPaint event.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
public class CircularProgressBar : Control
{
#region "Properties"
private Color _BorderColor;
public Color BorderColor
{
get { return _BorderColor; }
set
{
_BorderColor = value;
this.Invalidate();
}
}
private Color _InnerColor;
public Color InnerColor
{
get { return _InnerColor; }
set
{
_InnerColor = value;
this.Invalidate();
}
}
private bool _ShowPercentage;
public bool ShowPercentage
{
get { return _ShowPercentage; }
set
{
_ShowPercentage = value;
this.Invalidate();
}
}
private int _BorderWidth;
public int BorderWidth
{
get { return _BorderWidth; }
set
{
_BorderWidth = value;
this.Invalidate();
}
}
private float _Value;
public float Value
{
get { return _Value; }
set
{
_Value = value;
this.Invalidate();
}
}
#endregion
#region "Constructor"
public CircularProgressBar()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
_Value = 100;
_BorderColor = Color.Orange;
_BorderWidth = 30;
_ShowPercentage = true;
_InnerColor = Color.DarkGray;
this.ForeColor = Color.White;
}
#endregion
#region "Painting"
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//Measure the single parts
int Diameter = Math.Min(this.ClientSize.Width, this.ClientSize.Height);
int InnerDiameter = Diameter - BorderWidth;
Rectangle PieRect = new Rectangle(Convert.ToInt32(this.ClientSize.Width / 2 - Diameter / 2), Convert.ToInt32(this.ClientSize.Height / 2 - Diameter / 2), Diameter, Diameter);
Rectangle InnerRect = new Rectangle(Convert.ToInt32(this.ClientSize.Width / 2 - InnerDiameter / 2), Convert.ToInt32(this.ClientSize.Height / 2 - InnerDiameter / 2), InnerDiameter, InnerDiameter);
//Draw outer ring
using (SolidBrush b = new SolidBrush(BorderColor))
{
e.Graphics.FillPie(b, PieRect, 0, Value / 100 * 360);
}
//Draw inner ring
using (SolidBrush b = new SolidBrush(this._InnerColor))
{
e.Graphics.FillEllipse(b, InnerRect);
}
//Draw percentage
if (ShowPercentage)
{
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
using (SolidBrush b = new SolidBrush(this.ForeColor))
{
e.Graphics.DrawString(Convert.ToInt32(Value).ToString() + "%", this.Font, b, InnerRect, sf);
}
}
}
}
#endregion
}
The result:

ContainerControl Won't Draw Controls On Scroll Properly

I have a custom CheckListBox control that is supposed to function the same way as the CheckedListBox control but it is not. The problem is when I scroll down, the drawing gets all messed up. The container won't actually scroll down, it will just "jitter" the check boxes around, draw random lines, etc.
Update: I changed the code so the location of each CheckBox was set in the OnControlAdded method instead of the OnPaint method. It now scrolls fine, but the drawing is still messed up! The border is missing, the BackColor changes, the lines for the check boxes are not straight; just a whole mess of things. It works perfectly in the designer (the scrolling and drawing), but not when I run the program.
Here's the code for the control:
public class ChromeCheckListBox : ChromeContainerControl
{
[Description("Determines what corner(s) will be rounded.")]
public Utilities.RoundedRectangle.RectangleCorners Corners { get; set; }
private int cornerRadius;
[Description("Determines the radius of the the corners")]
public int CornerRadius
{
get { return cornerRadius; }
set
{
if (value < 1)
Utilities.ThrowError("The radius cannot be less than 1. If you want no radius, set Corners to None.");
else
cornerRadius = value;
}
}
[Description("Determines the list of ChromeRadioButton controls that are displayed.")]
private ChromeCheckBox[] items;
public ChromeCheckBox[] Items
{
get { return items; }
set
{
items = value;
Controls.Clear();
Controls.AddRange(items);
}
}
public ChromeCheckListBox()
{
this.AutoScroll = true;
this.Corners = Utilities.RoundedRectangle.RectangleCorners.All;
this.CornerRadius = 1;
this.Items = new ChromeCheckBox[0];
this.Size = new Size(100, 100);
}
protected override void OnControlAdded(ControlEventArgs e)
{
for (int i = 0; i < Items.Length; i++)
{
if (i == 0)
Items[i].Location = new Point(2 + Padding.Left, 2 + Padding.Top);
else
Items[i].Location = new Point(2 + Padding.Left, Items[i - 1].Location.Y + Size.Ceiling(this.CreateGraphics().MeasureString(Items[i - 1].Text, Items[i - 1].Font)).Height);
}
base.OnControlAdded(e);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics canvas = e.Graphics;
canvas.SmoothingMode = SmoothingMode.HighQuality;
Rectangle region = new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
GraphicsPath path = Utilities.RoundedRectangle.Create(region, CornerRadius, Corners);
canvas.FillPath(new LinearGradientBrush(region, fillColors[0], fillColors[1], 90), path);
canvas.DrawPath(new Pen(borderColor), path);
}
}
I got it! Instead of setting the location of the check boxes in the OnPaint method, I should set them in the OnControlAdded method. Also, on the OnScroll method, I need to Invalidate the control causing it to redraw.
So, it should (well maybe not should, but could) look like this:
public class ChromeCheckListBox : ChromeContainerControl
{
[Description("Determines what corner(s) will be rounded.")]
public Utilities.RoundedRectangle.RectangleCorners Corners { get; set; }
private int cornerRadius;
[Description("Determines the radius of the the corners")]
public int CornerRadius
{
get { return cornerRadius; }
set
{
if (value < 1)
Utilities.ThrowError("The radius cannot be less than 1. If you want no radius, set Corners to None.");
else
cornerRadius = value;
}
}
[Description("Determines the list of ChromeRadioButton controls that are displayed.")]
private ChromeCheckBox[] items;
public ChromeCheckBox[] Items
{
get { return items; }
set
{
items = value;
Controls.Clear();
Controls.AddRange(items);
}
}
public ChromeCheckListBox()
{
this.AutoScroll = true;
this.Corners = Utilities.RoundedRectangle.RectangleCorners.All;
this.CornerRadius = 1;
this.Items = new ChromeCheckBox[0];
this.Size = new Size(100, 100);
}
protected override void OnControlAdded(ControlEventArgs e)
{
for (int i = 0; i < Items.Length; i++)
{
if (i == 0)
Items[i].Location = new Point(2 + Padding.Left, 2 + Padding.Top);
else
Items[i].Location = new Point(2 + Padding.Left, Items[i - 1].Location.Y + Size.Ceiling(this.CreateGraphics().MeasureString(Items[i - 1].Text, Items[i - 1].Font)).Height);
}
base.OnControlAdded(e);
}
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
base.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics canvas = e.Graphics;
canvas.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle region = new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
GraphicsPath path = Utilities.RoundedRectangle.Create(region, CornerRadius, Corners);
canvas.FillPath(new LinearGradientBrush(region, fillColors[0], fillColors[1], 90), path);
canvas.DrawPath(new Pen(borderColor), path);
}

C# vertical label in a Windows Forms

Is it possible to display a label vertically in a Windows Forms?
Labels are easy, all you have to do is override the Paint event and draw the text vertically. Do note that GDI is optimised for Drawing text horizontally. If you rotate text (even if you rotate through multiples of 90 degrees) it will looks notably worse.
Perhaps the best thing to do is draw your text (or get a label to draw itself) onto a bitmap, then display the bitmap rotated.
Some C# code for drawing a Custom Control with vertical text. Note that ClearType text NEVER works if the text is not horizontal:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public partial class VerticalLabel : UserControl
{
public VerticalLabel()
{
InitializeComponent();
}
private void VerticalLabel_SizeChanged(object sender, EventArgs e)
{
GenerateTexture();
}
private void GenerateTexture()
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
format.Trimming = StringTrimming.EllipsisCharacter;
Bitmap img = new Bitmap(this.Height, this.Width);
Graphics G = Graphics.FromImage(img);
G.Clear(this.BackColor);
SolidBrush brush_text = new SolidBrush(this.ForeColor);
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
G.DrawString(this.Name, this.Font, brush_text, new Rectangle(0, 0, img.Width, img.Height), format);
brush_text.Dispose();
img.RotateFlip(RotateFlipType.Rotate270FlipNone);
this.BackgroundImage = img;
}
}
Create a class myLabel which can rotate it's Text on any angle specified by you.
You can use it by code or simply dragging from ToolBox
using System.Drawing;
class myLabel:System.Windows.Forms.Label
{
public int RotateAngle { get; set; } // to rotate your text
public string NewText { get; set; } // to draw text
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Brush b =new SolidBrush(this.ForeColor);
e.Graphics.TranslateTransform(this.Width / 2, this.Height / 2);
e.Graphics.RotateTransform(this.RotateAngle);
e.Graphics.DrawString(this.NewText, this.Font,b , 0f, 0f);
base.OnPaint(e);
}
}
Now this custom control is used into your form.
You have to set below properties
1. mylbl.Text = ""; //which can be changed by NewText property
2. mylbl.AutoSize = false; // adjust according to your text
3. mylbl.NewText = "Hello"; // whatever you want to display
4. mylbl.ForeColor = Color.Red; // color to display
5. mylbl.RotateAngle = -90; //angle to rotate
I expanded on Javed Akram's answer to resize the widget automatically (I needed this feature). It works for both positive and negative angles, the way that Javed states:
1. mylbl.Text = ""; // which can be changed by NewText property
2. mylbl.AutoSize = false; // adjust according to your text
3. mylbl.NewText = "Hello"; // whatever you want to display
4. mylbl.ForeColor = Color.Red; // color to display
5. mylbl.RotateAngle = -90; // angle to rotate
Here is the code:
public class RotatingLabel : System.Windows.Forms.Label
{
private int m_RotateAngle = 0;
private string m_NewText = string.Empty;
public int RotateAngle { get { return m_RotateAngle; } set { m_RotateAngle = value; Invalidate(); } }
public string NewText { get { return m_NewText; } set { m_NewText = value; Invalidate(); } }
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Func<double, double> DegToRad = (angle) => Math.PI * angle / 180.0;
Brush b = new SolidBrush(this.ForeColor);
SizeF size = e.Graphics.MeasureString(this.NewText, this.Font, this.Parent.Width);
int normalAngle = ((RotateAngle % 360) + 360) % 360;
double normaleRads = DegToRad(normalAngle);
int hSinTheta = (int)Math.Ceiling((size.Height * Math.Sin(normaleRads)));
int wCosTheta = (int)Math.Ceiling((size.Width * Math.Cos(normaleRads)));
int wSinTheta = (int)Math.Ceiling((size.Width * Math.Sin(normaleRads)));
int hCosTheta = (int)Math.Ceiling((size.Height * Math.Cos(normaleRads)));
int rotatedWidth = Math.Abs(hSinTheta) + Math.Abs(wCosTheta);
int rotatedHeight = Math.Abs(wSinTheta) + Math.Abs(hCosTheta);
this.Width = rotatedWidth;
this.Height = rotatedHeight;
int numQuadrants =
(normalAngle >= 0 && normalAngle < 90) ? 1 :
(normalAngle >= 90 && normalAngle < 180) ? 2 :
(normalAngle >= 180 && normalAngle < 270) ? 3 :
(normalAngle >= 270 && normalAngle < 360) ? 4 :
0;
int horizShift = 0;
int vertShift = 0;
if (numQuadrants == 1)
{
horizShift = Math.Abs(hSinTheta);
}
else if (numQuadrants == 2)
{
horizShift = rotatedWidth;
vertShift = Math.Abs(hCosTheta);
}
else if (numQuadrants == 3)
{
horizShift = Math.Abs(wCosTheta);
vertShift = rotatedHeight;
}
else if (numQuadrants == 4)
{
vertShift = Math.Abs(wSinTheta);
}
e.Graphics.TranslateTransform(horizShift, vertShift);
e.Graphics.RotateTransform(this.RotateAngle);
e.Graphics.DrawString(this.NewText, this.Font, b, 0f, 0f);
base.OnPaint(e);
}
}
I found a way to simply do it without adding code or classes to your project!
When you create your label, simply add:
this.label1.text = "V\nE\nR\nT\nI\nC\nA\nL\n";
This worked for me!
You can rotate text instead of the label control in the OnPaint event or Paint method:
private void uc1_Paint(object sender, PaintEventArgs e)
{
string Name;
var g = e.Graphics;
g.DrawString(Name, new Font("Tahoma", 8), Brushes.Black, 0, 0,
new StringFormat(StringFormatFlags.DirectionVertical));
}
2015 update on an old post. Since most of the other answers seem to heavily affect VS2013's designer in terms of usability, I'd suggest this solution:
http://www.codeproject.com/Articles/19774/Extended-Vertical-Label-Control-in-C-NET
It absolutely works. I found it on net and little changed
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.ComponentModel;
public class VerticalLabel : System.Windows.Forms.Label
{
private bool bFlip = true;
public VerticalLabel()
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
stringFormat.FormatFlags = StringFormatFlags.DirectionVertical;
Brush textBrush = new SolidBrush(this.ForeColor);
Matrix storedState = g.Transform;
if (bFlip)
{
g.RotateTransform(180f);
g.TranslateTransform(-ClientRectangle.Width,-ClientRectangle.Height);
}
g.DrawString(
this.Text,
this.Font,
textBrush,
ClientRectangle,
stringFormat);
g.Transform = storedState;
}
[Description("When this parameter is true the VLabel flips at 180 degrees."),Category("Appearance")]
public bool Flip180
{
get
{
return bFlip;
}
set
{
bFlip = value;
this.Invalidate();
}
}
}
Used pieces from others
Jeremy
public partial class VerticalLabel_UserControl : UserControl
{
private IComponentChangeService _changeService;
private string strPropertyText = "Vertical Text";
public VerticalLabel_UserControl()
{
InitializeComponent();
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Bindable(true)]
public override string Text { get { return base.Text; } set { base.Text = value; this.Invalidate(); } }
private void VerticalLabel_UserControl_SizeChanged(object sender, EventArgs e)
{
GenerateTexture();
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
}
private void GenerateTexture()
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
// format.Trimming = StringTrimming.EllipsisCharacter;
Bitmap img = new Bitmap(this.Height, this.Width);
Graphics G = Graphics.FromImage(img);
G.Clear(this.BackColor);
SolidBrush brush_text = new SolidBrush(this.ForeColor);
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
G.DrawString(this.strPropertyText, this.Font, brush_text, new Rectangle(0, 0, img.Width, img.Height), format);
img.RotateFlip(RotateFlipType.Rotate270FlipNone);
this.BackgroundImage = img;
brush_text.Dispose();
}
public override System.ComponentModel.ISite Site
{
get
{
return base.Site;
}
set
{
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
base.Site = value;
if (!DesignMode)
return;
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
}
}
private void OnComponentChanged(object sender, ComponentChangedEventArgs ce)
{
VerticalLabel_UserControl label = ce.Component as VerticalLabel_UserControl;
if (label == null || !label.DesignMode)
return;
if (((IComponent)ce.Component).Site == null || ce.Member == null || ce.Member.Name != "Text")
return;
//Causes the default text to be updated
string strName = this.Name.ToLower();
string strText = this.Text.ToLower();
if (strText.Contains(strName))
{
this.Text = "Vertical Text";
}
else
{
strPropertyText = this.Text;
}
//Prints the text vertically
GenerateTexture();
}
}
I just turned off the AutoSize property and resized the label vertically. I made the label wide enough for only one character. Then I changed TextAlign to center to make the alignment look better. This worked great for me.

Categories

Resources