Reasons for why a WinForms label does not want to be transparent?
Asked Answered
C

11

29

Why can't I set the BackColor of a Label to Transparent? I have done it before, but now it just don't want to...

I created a new UserControl, added a progressbar and a label to it. When I set the BackColor of the label to transparent it is still gray =/ Why is this?

What I wanted was to have the label on top of the progressbar so that its text was "in" the progressbar...

Charles answered 3/3, 2009 at 10:46 Comment(2)
See alexander willemse's answer.Quizzical
Regarding your last sentence (putting a text into the progressbar): Progress bars guidelines from Microsoft say: Don't put the percentage complete or any other text on a progress bar. Such text isn't accessible and isn't compatible with using themes. So if you can find another way, it will be more compatible and it will look better and more consistent. Please see the guidelines linked above.Luciferous
I
14

WinForms doesn't really support transparent controls, but you can make a transparent control yourself. See my answer here.

In your case you should probably subclass the progress bar and override the OnPaint method to draw a text on the progress bar.

Insolence answered 3/3, 2009 at 10:57 Comment(3)
how would you draw the text on the progress bar?Charles
I haven't done this for a progress bar, but you can create an overload for the OnPaint method. Here you first call base.OnPaint and then use the graphics object passed in the event arguments to draw the text on top of the control.Insolence
Not sure why an answer which refers to an other SO answer, which says 'look it up on Google' rather than give the vital details of the method, was accepted when the complete solution is given in another answer on this page.Lightning
C
32

Add a new class to your project and post the code shown below. Build. Drop the new control from the top of the toolbox onto your form.

using System;
using System.Windows.Forms;

public class TransparentLabel : Label {
  public TransparentLabel() {
    this.SetStyle(ControlStyles.Opaque, true);
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
  }
  protected override CreateParams CreateParams {
    get {
      CreateParams parms = base.CreateParams;
      parms.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
      return parms;
    }
  }
}
Charlatanism answered 3/3, 2009 at 21:22 Comment(6)
Well, this almost seems to work. Problem is when it is ontop of a progressbar. It seems like the text disappears and reappears sometimes...Charles
Stacking effects are not supported, it can only track changes to the container.Charlatanism
so, like if I changed the background color of the user control? (and there was no progress bar between them?)Charles
Right. Or anything else drawn on the container.Charlatanism
I found out the hard way that if you omit the constructor Hans put in, it seems to work until you set the Enabled to false, at which point the transparency is lost.Stonework
For some reason this makes buttons appear behind my labels. Buttons that appear in a completely different spot in the same window.Barron
I
14

WinForms doesn't really support transparent controls, but you can make a transparent control yourself. See my answer here.

In your case you should probably subclass the progress bar and override the OnPaint method to draw a text on the progress bar.

Insolence answered 3/3, 2009 at 10:57 Comment(3)
how would you draw the text on the progress bar?Charles
I haven't done this for a progress bar, but you can create an overload for the OnPaint method. Here you first call base.OnPaint and then use the graphics object passed in the event arguments to draw the text on top of the control.Insolence
Not sure why an answer which refers to an other SO answer, which says 'look it up on Google' rather than give the vital details of the method, was accepted when the complete solution is given in another answer on this page.Lightning
E
9

Most simple solution is following:

  1. Set background color to transparency either in visual editor or in constructor of your form:

    this.label1.BackColor = System.Drawing.Color.Transparent;

  2. Set Parent property of your label to control that you want to be visible behind the text. This can be done in form constructor or in Load method:

    this.label1.Parent = progressBar1;

Its true that this is not true transparency as in DirectX. The result you see on display is composed only from two layers. You cant sum up more than two layers with this approach (each layer having its own transparency defined by alpha parameter). But its suitable for many practical situations you can encounter in Winforms programming.

Enrol answered 9/8, 2011 at 7:33 Comment(0)
W
5

Use a LinkLabel not a normal Label

    private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel)
    {
        this.MakeTransparentLabel(LinkLabel, Color.White);
    }
    private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel, Color ForeColor)
    {
        LinkLabel.ForeColor = ForeColor;
        LinkLabel.LinkColor = ForeColor;
        LinkLabel.VisitedLinkColor = ForeColor;
        LinkLabel.ActiveLinkColor = ForeColor;
        LinkLabel.DisabledLinkColor = ForeColor;
        LinkLabel.LinkArea = new LinkArea(0, 0);
        LinkLabel.LinkBehavior = LinkBehavior.NeverUnderline;
        LinkLabel.Cursor = Cursors.Arrow;
        LinkLabel.BackColor = Color.Transparent;
    }
    private void SetTransparentLabelText(System.Windows.Forms.LinkLabel LinkLabel, string Text)
    {
        if (string.IsNullOrEmpty(Text)) { LinkLabel.Text = " "; return; }
        LinkLabel.Text = Text;
    }
Wicked answered 25/3, 2011 at 21:50 Comment(0)
D
3

This is a very simple solution and works great:

public class MyLabel : Label
{
    private bool fTransparent = false;
    public bool Transparent
    {
        get { return fTransparent; }
        set { fTransparent = value; }
    }
    public MyLabel() : base()
    {
    }
    protected override CreateParams CreateParams
    {
        get
        {
            if (fTransparent)
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
                return cp;
            }
            else return base.CreateParams;
        }
    }
    protected override void WndProc(ref Message m)
    {
        if (fTransparent)
        {
            if (m.Msg != 0x14 /*WM_ERASEBKGND*/ && m.Msg != 0x0F /*WM_PAINT*/)
                base.WndProc(ref m);
            else 
            {
                if (m.Msg == 0x0F) // WM_PAINT
                    base.OnPaint(new PaintEventArgs(Graphics.FromHwnd(Handle), ClientRectangle));
                DefWndProc(ref m);
            }
        }
        else base.WndProc(ref m);
    }
}

When label backcolor is transparent, then label only takes picture of its underlying control the first time when it is created, after that label backcolor is constant. And each time when label repaints itself, it repaints to that fixed color or pattern.

Overriding CreateParams affects on how window for control will be created, this enables real transparency.

Overriding WndProc you control which messages should be passed to base class. We must filtrate WM_ERASEBKGND and WM_PAINT, but we also have to trigger paint event.

Devondevona answered 12/2, 2014 at 10:54 Comment(2)
Would that work on top of a moving progress bar though?Charles
It should work, because that's the way how to tell native underlaying control not to paint itself.Devondevona
G
1

If you want to focus on designing your windows application, I suggest you use WPF.

Making controles transparent in WPF is very easy.

<TextBox Width="200" Height="40" Opacity="0.5"/>
Gelid answered 3/3, 2009 at 11:13 Comment(1)
I'm sure WPF does transparent labels correctly, however just wanted to point out that the code in this example, if applied to a Label, would make the text semitransparent too - which is NOT desired!Pilcher
S
1

Here is a transparent control I wrote a while ago which displays rotated text. Most of the code comes from here, though IIRC I had to make a few tweaks to get it to work.

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;

namespace MyNamespace
{
    public partial class RotatedText : UserControl
    {
        private readonly Timer _invalidationTimer;
        private const int WS_EX_TRANSPARENT = 0x00000020;

        public RotatedText()
        {
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            InitializeComponent();

            _invalidationTimer = new Timer {Interval = 500, Enabled = true};
            _invalidationTimer.Tick += TickHandler;
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        [Description("Text which appears in control")]
        public string Text { get; set; }

        #region Transparent background
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= WS_EX_TRANSPARENT;
                return cp;
            }
        }

        private void TickHandler(object sender, EventArgs e)
        {
            InvalidateEx();
        }

        private void InvalidateEx()
        {
            if (Parent != null)
                Parent.Invalidate(Bounds, false);
            else
                Invalidate();
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //Intentionally do nothing - stops background from drawing
            //base.OnPaintBackground(e);
        } 
        #endregion

        //Rotate text and draw
        protected override void OnPaint(PaintEventArgs e)
        {
            double angleRadians = Math.Atan2(Height, Width);
            float angleDegrees = -1*(float) (angleRadians*180/Math.PI);
            angleDegrees *= 0.9f;
            e.Graphics.RotateTransform(angleDegrees, MatrixOrder.Append);
            e.Graphics.TranslateTransform(20, Height - 75, MatrixOrder.Append);
            e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
            Font font = new Font("Ariel", 50);
            e.Graphics.DrawString(Text, font, Brushes.Gray, 1, 2); //Shadow
            e.Graphics.DrawString(Text, font, Brushes.Red, 0, 0);
        }
    }
}
Stringendo answered 26/5, 2010 at 14:54 Comment(0)
C
0

So as the comment to my previous answer stated, Control is the default behaviour, and is what I remembered as being Transparent.

Anyway, have you tried setting the background property of your UserControl, or the container your label is in (Panel, Form, whatever?), your label should reflect that color :)


Old Answer: Its been a while since I did winforms programming, but as I recall labels are transparent per default? thus its only the text that gets an actual color and the bacground color mimics whatever is behind it :)

Cyzicus answered 3/3, 2009 at 10:50 Comment(2)
No, Label by default has a Background of Control. However, you're right in that setting it to Transparent does mimic the colour of the control that's hosting it, so it paints the background as solid gray.Bolzano
Should have fired up WinForms and checked :P, true Control is the default behaviour, it just seems transparent because they share the same color :)Cyzicus
D
0

It is possible to do exactly what you want to achieve. It just takes a little time to play with controls. It is possible to create a Label control with transparent background, and place it on top of Progressbar control.

Check my answer to another SO question.

Dragonnade answered 5/10, 2009 at 17:30 Comment(0)
Y
0

as to an explanation for your problem, windows doesn't do transparency for background controls like you'd expect-i'm guessing the gray background is actually the form's surface. whatever controls are drawn between the form surface and your label are ignored.

Yawmeter answered 5/10, 2009 at 17:42 Comment(0)
D
-3

Select BackColor, go the Web tab, and select Transparent. Generates the following.

        this.label1.BackColor = System.Drawing.Color.Transparent;
Decided answered 13/2, 2010 at 3:1 Comment(1)
That's what I did, but it doesn't work when on top of a progress bar :)Charles

© 2022 - 2024 — McMap. All rights reserved.