Click here to Skip to main content
Click here to Skip to main content

A Transparent/Translucent Label Control with Moving Caption

By , 16 Aug 2007
 

Introduction

This article describes the creation of a Label custom control that can be translucent to the background.

The Transparent Label Source Code

Screenshot - Lotus.jpg

The Transparent Label has twelve added properties

  • BackColor - Gets or sets the background color of the control.
  • Opacity - The alpha value used to blend the control's background. Valid values are 0 through 255.
  • Radius - Radius of rounded borders.
  • ShapeBorderStyle - Style of border to be drawn around the control.
  • BorderColor - The color of border to be drawn around the control.
  • Caption - The text associated with the control.
  • Font - The font used to display text in the control.
  • Forecolor - The foreground color of this component which is used to display the text.
  • TextAlign - Text alignment (Left, Right or Center) only with Moving None.
  • Moving - Text Moving (None, RightToLeft, DownToUp, LeftToRight, UpToDown).
  • MovingActive - Activate the text movement.
  • DimmedColor - Dims the text color when the mouse is passing over the control.

    The OnPaint call has three simple methods, DrawBorder, DrawLabelBackground, DrawText.

    This is the OnPaint method

    protected override void OnPaint(PaintEventArgs e)
    {
        SmoothingMode sm = e.Graphics.SmoothingMode;
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        if (_borderStyle == ShapeBorderStyles.ShapeBSFixedSingle)
            DrawBorder(e.Graphics);
        DrawLabelBackground(e.Graphics);
        DrawText(e);
        e.Graphics.SmoothingMode = sm;
    }

    This is the DrawBorder method:

    private void DrawBorder(Graphics g)
    {
        Rectangle rect = this.ClientRectangle;
        rect.Width--;
        rect.Height--;
        using (GraphicsPath bp = GetPath(rect, _radius))
        {
            using (Pen p = new Pen(_borderColor))
            {
                g.DrawPath(p, bp);
            }
        }
    }

    This is the DrawLabelBackground method:

    private void DrawLabelBackground(Graphics g)   
    {
        Rectangle rect = this.ClientRectangle;
        iRect = rect;
        rect.X++;
        rect.Y++;
        rect.Width -= 2;
        rect.Height -= 2;
        using (GraphicsPath bb = GetPath(rect, _radius))
        {
            using (Brush br = new SolidBrush(
                Color.FromArgb(_opacity, _backColor)))
            {
                g.FillPath(br, bb);
            }
        }
    }

    This is the GetPath method, called by DrawBorder and DrawLabelBackground

    protected GraphicsPath GetPath(Rectangle rc, int r)
    //  Build the path with the round corners in the rectangle
    //  r is the radious of rounded corner.
    {
        int x = rc.X, y = rc.Y, w = rc.Width, h = rc.Height;
        r = r << 1;
        GraphicsPath path = new GraphicsPath();
        if (r > 0)
            //  If the radious of rounded corner is greater than one side then
            //  do the side rounded
        {
            if (r > h) { r = h; };                           //Rounded
            if (r > w) { r = w; };                           //Rounded
            path.AddArc(x, y, r, r, 180, 90);                //Upper left corner
            path.AddArc(x + w - r, y, r, r, 270, 90);        //Upper right corner
            path.AddArc(x + w - r, y + h - r, r, r, 0, 90);  //Lower right corner
            path.AddArc(x, y + h - r, r, r, 90, 90);         //Lower left corner
            path.CloseFigure();
        }
        else
            // If the radious of rounded corner is zero then the path is 
            // a rectangle
        {
            path.AddRectangle(rc);
        }
    
        return path;
    }

    This is DrawText method.

    protected void DrawText(PaintEventArgs pe)
    {
        //This is a workaround to get MeasureString to work properly
        //pe.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
        SizeF sz = pe.Graphics.MeasureString(_text, base.Font);
        switch (_moving)
        {
        case MoveType.None:
            NoMove();
            break;
        case MoveType.RightToLeft:
            MoveRightToLeft();
            break;
        case MoveType.DownToUp:
            MoveDownToUp();
            break;
        case MoveType.LeftToRight:
            MoveLeftToRight();
            break;
        case MoveType.UpToDown:
            MoveUpToDown();
            break;
        }
        //Rectangle bounds for the text
        txtRect = new Rectangle(this.pointX, this.pointY,
            (int)sz.Width + 1, (int)sz.Height);
        //If the mouse is passing over the text it is selected and will be dimmed
        //otherwise nothing.
        Brush brText = new SolidBrush(base.ForeColor);
        Brush brTextDimmed = new SolidBrush(_dimmedColor);
        if (_isSelected)
            pe.Graphics.DrawString(_text,
            base.Font,
            brTextDimmed,
            txtRect);
        else
            pe.Graphics.DrawString(_text,
            base.Font,
            brText,
            txtRect);
    }

    The methods NoMove(), MoveRigntToLeft(), MoveDownToUp(), MoveLeftToRight() and MoveUpToDown()updates, for each MoveType, the coordinates of text rectangle.

    protected void NoMove()
    {
        //Align text
        switch (_textAlign)
        {
        case TextAlignment.Left:
            pointX = (int)this.iRect.X;
            break;
        case TextAlignment.Center:
            pointX = (this.iRect.Width - this.txtRect.Width) / 2;
            break;
        case TextAlignment.Right:
            pointX = (this.iRect.Width - this.txtRect.Width);
            break;
        }
        pointY = (this.iRect.Height - this.txtRect.Height) / 2;
    }
    protected void MoveRightToLeft()
    {
        if (pointX < -this.txtRect.Width)
        { pointX = this.iRect.X + this.iRect.Width; }
        else
        { pointX -= 2; }
        pointY = (this.iRect.Height - this.txtRect.Height) / 2;
    }
    protected void MoveDownToUp()
    {
        pointX = (this.iRect.Width - this.txtRect.Width) / 2;
        if (pointY < -this.txtRect.Height)
        { pointY = (int)this.iRect.Y + this.iRect.Height; }
        else
        { pointY -= 2; }
    }
    protected void MoveLeftToRight()
    {
        if (pointX > this.iRect.X + this.iRect.Width)
        { pointX = this.iRect.X - this.txtRect.Width; }
        else
        { pointX += 2; }
        pointY = (this.iRect.Height - this.txtRect.Height) / 2;
    }
    protected void MoveUpToDown()
    {
        pointX = (this.iRect.Width - this.txtRect.Width) / 2;
        if (pointY > this.iRect.Y + this.iRect.Height)
        { pointY = (int)this.iRect.Y - this.iRect.Height; }
        else
        { pointY += 2; }
    }

    If the mouse is passing over the text it will be dimmed, for that we use events OnMouseEnter and OnMouseLeave.

    protected override void OnMouseEnter(EventArgs e)
    {
        base.OnMouseEnter(e);
        _isSelected = true;
        this.Invalidate();
    }
    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        _isSelected = false;
        this.Invalidate();
    }

    This component uses a timer to update and invalidate the Draw event OnPaint.

    private void timer1_Tick(object sender, System.EventArgs e)
    {
        this.Update();
        this.Invalidate();
    }

    Thanks

    I'd like express my gratitude to Andreas for to fix the bug in my article "Two First Controls -A Shape and an Inherited Label Control" and to Jason (Apuhjee) who inspired this new article for your interest in if there was a way to alpha blend the shape with the background.

    History

    12/08/2007 First Version.

  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    Daniel Ortiz Acuna
    Web Developer
    Argentina Argentina
    Member
    No Biography provided

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    Suggestioni hope it can support display mulitline wordsmemberplaodj23 May '12 - 6:06 
    i hope it can support display mulitline words
     
    add the WordWrap property
     
    thanks
    GeneralMy vote of 5memberplaodj23 May '12 - 6:00 
    good
    GeneralSmall modification to the Component Class DAOTransparentLabel on Region Metthods to Solve Problem of Text Centerlizationmemberkshadway27 Nov '09 - 5:35 
    You have to change all the text that contains ( this.txtRect ) inside ( Component Class DAOTransparentLabel on Region Metthods) to Solve Problem of Text Centerlizationthat as the following :
     
    1 - Declare Varaible [SizeF sz = pe.Graphics.MeasureString(_text, base.Font)] to use [(int)(sz.Width)] instead of [this.txtRect.Width] and [(int)(sz.Height)] instead of [this.txtRect.Height].
     
    3 - Replace [(this.iRect.Width - this.txtRect.Width) / 2] to [(this.iRect.Width / 2) - ((int)(sz.Width) / 2)].
     
    4 - Replace [(this.iRect.Height - this.txtRect.Height) / 2] to [(this.iRect.Height / 2) - ((int)(sz.Height) / 2)].
     
    I hope this will help.
     
    Many thanks to Daniel Ortiz Acuna.
     
    khalid shadway

    GeneralA really nice effort !!memberdamon8818 Nov '09 - 4:44 
    thanks for developing this control. A well written code and above all provides all the functionality that a Label Control should provide.
     
    Infact i am creating my own Multimedia List View Control and i am going to use your Label Control in it. Soon ill be posting it here.
     
    Cheers Wink | ;)
    Generalonly translucent to windows form background imagememberjtby211 Sep '09 - 12:03 
    I can only make it translucent to the forms background image. Is there any way to make it translucent to a control placed underneath the label control, so you can see the control underneath?
     
    Thx.
    GeneralThanks for you controlmemberk^s5 Mar '08 - 5:37 
    I was searching for a transparent label example for a week and the only solution i've found is that:
     
    ///
    /// A label that can be transparent.
    ///

    public class TransparentLabel : Control
    {
    ///
    /// Creates a new instance.
    ///

    public TransparentLabel()
    {
    TabStop = false;
    }
     
    ///
    /// Gets the creation parameters.
    ///

    protected override CreateParams CreateParams
    {
    get
    {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x20;
    return cp;
    }
    }
     
    ///
    /// Paints the background.
    ///

    /// E.
    protected override void OnPaintBackground(PaintEventArgs e)
    {
    // do nothing
    }
     
    ///
    /// Paints the control.
    ///

    /// E.
    protected override void OnPaint(PaintEventArgs e)
    {
    using (SolidBrush brush = new SolidBrush(ForeColor))
    {
    e.Graphics.DrawString(Text, Font, brush, -1, 0);
    }
    }
    }

     
    But this is a very poor solution because it doens't inherits from Label.
     
    Now, reviewing your label, i'created this REAL transparent LABEL:
     
    ///
    /// Inherits directly from Label so it is
    /// really a System.Windows.Forms.Label
    ///

    public class TransparentLabel : Label
    {
    ///
    /// At the constructor the styles are setted
    /// to be able to paint correctly the label.
    ///

    public TransparentLabel()
    {
    base.BackColor = Color.Transparent;
    SetStyle(
    ControlStyles.AllPaintingInWmPaint
    | ControlStyles.OptimizedDoubleBuffer
    | ControlStyles.ResizeRedraw
    | ControlStyles.SupportsTransparentBackColor
    | ControlStyles.UserPaint, true);
     
    SetStyle(ControlStyles.Opaque, false);
    UpdateStyles();
    }
     
    ///
    /// Overriding the OnPaint method allows to paint
    /// the transparent background using Alpha = 0 and any color. (1)
    ///
    /// In order to let the label paint whatever it wants, after
    /// painting the background, I'm sending to the base
    /// de pevent on its OnPaint method. (2)
    ///

    protected override void OnPaint(PaintEventArgs pevent)
    {
    /// (1)
    using (Brush br = new SolidBrush(Color.FromArgb(0, Color.White)))
    {
    pevent.Graphics.FillRectangle(br, ClientRectangle);
    }
     
    /// (2)
    base.OnPaint(pevent);
    }
    }

     
    So i must thank you t show me the way, it works perfect!
    GeneralStrange alignment errormemberJohnny J.24 Jan '08 - 6:09 
    I drop a DOATransparentLabel on my form, and the ONLY thing I change is that I make it smaller. What happens is that the text is centered when I look at the label in the IDE form designer, but when I run my application, the text is no longer centered in the label, but shows in the bottom right area (sort of like where it would have been if the label had had it's original size...
     
    Any idea why?
     
    Cheers,
    Johnny J.
     
    Otherwise: Nice Work!
    GeneralRe: Strange alignment errormemberJohnny J.24 Jan '08 - 6:11 
    My Spanish is limited, but I think the previous comment was about that too...
     
    Would be nice if comments were made in English so that everybody could understand them...
     
    Cheers,
    Johnny J.
    AnswerRe: Strange alignment errormemberMorenosoft28 Jan '08 - 23:25 
    During the DrawText function the pointX is calculated based on the values given in txtRect.
    The first time this control is drawn, the txtRect.Width and txtRect.Height are still 0.
     
    The easiest way to solve this, is to add the following code in DrawText:
     
    //put the new code right after this line:
    SizeF sz = pe.Graphics.MeasureString(_text, base.Font);
     
    //Add this to initialize with the correct width and height
    txtRect.Width = (int)sz.Width;
    txtRect.Height = (int)sz.Height;

    GeneralRe: Strange alignment errormemberJohnny J.29 Jan '08 - 3:08 
    Great - THANKS!
     
    /Johnny J.

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web01 | 2.6.130523.1 | Last Updated 16 Aug 2007
    Article Copyright 2007 by Daniel Ortiz Acuna
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid