简体   繁体   中英

C# vertical label in a Windows Forms

是否可以在Windows 窗体<\/a>中垂直显示标签?

"

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

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();
    }
}

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();
        }
    }
}

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.

All this code for rotating a text. Wow

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM