Show a Label with semi-transparent BackColor above other controls?
Asked Answered
I

1

5

I've got a custom control with two PictureBox controls that are animated and a label control over them.

The child indexes are set so that label is always on top but the picture boxes are interchanging so when animated they display different images each time.

As I understand, label needs to have a parent control on top of which it can support a semi transparent color (Argb). Since the label has active picture box as its parent it will also be animated with which is not what I want at all.

Is there a way to fix a child position relative to parents parent?

Igenia answered 17/12, 2015 at 12:56 Comment(7)
You cannot achieve this effect in WinForms as the platform does not support true control variable opacity. "Transparent backgrounds" are implemented as a hack that makes the root parent (the underlying Form) repaint it's background. You cannot successfully layer multiple transparent controls on top.Impersonate
@Impersonate - I thought so too but hoped for better ;). Is there any other way to achieve similar effect using win forms. I've seen DevXpress people make controls with similar effect so I wanted to give it a try. Any other solution that do not include WPF or going from win forms?Igenia
@Igenia Let me know if I understand your question correctly: Do you need to have a transparent label above your picture box that only shows the text?Hilly
@Reza Aghaei - Not quite. I want a semi-transparent color over animated picture boxes. I want to create something similar to windows tile.Igenia
@Dino, can you show us what have you tried?Hemispheroid
@Igenia Being animated makes no difference. Do you need semi-transparent background color for the label or or semi-transparent fore color for Label?Hilly
@Reza Aghaei - Background color onlyIgenia
H
10

To have a transparent label control, you can override the OnPaint method and draw all controls that intersects with label, at last draw the background and text of the label.

Also when moving your picture boxes, don't forget to call the Invalidate() method of the transparent label.

Screenshot

enter image description here

Sample Implementation

public class TransparentLabel : Label
{
    public TransparentLabel()
    {
        this.transparentBackColor = Color.Blue;
        this.opacity = 50;
        this.BackColor = Color.Transparent;
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        if (Parent != null)
        {
            using (var bmp = new Bitmap(Parent.Width, Parent.Height))
            {
                Parent.Controls.Cast<Control>()
                      .Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
                      .Where(c => c.Bounds.IntersectsWith(this.Bounds))
                      .OrderByDescending(c => Parent.Controls.GetChildIndex(c))
                      .ToList()
                      .ForEach(c => c.DrawToBitmap(bmp, c.Bounds));


                e.Graphics.DrawImage(bmp, -Left, -Top);
                using (var b = new SolidBrush(Color.FromArgb(this.Opacity, this.TransparentBackColor)))
                {
                    e.Graphics.FillRectangle(b, this.ClientRectangle);
                }
                e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
                TextRenderer.DrawText(e.Graphics, this.Text, this.Font, this.ClientRectangle, this.ForeColor, Color.Transparent);
            }
        }
    }

    private int opacity;
    public int Opacity
    {
        get { return opacity; }
        set
        {
            if (value >= 0 && value <= 255)
                opacity = value;
            this.Invalidate();
        }
    }

    public Color transparentBackColor;
    public Color TransparentBackColor
    {
        get { return transparentBackColor; }
        set
        {
            transparentBackColor = value;
            this.Invalidate();
        }
    }

    [Browsable(false)]
    public override Color BackColor
    {
        get
        {
            return Color.Transparent;
        }
        set
        {
            base.BackColor = Color.Transparent;
        }
    }
}
Hilly answered 17/12, 2015 at 16:1 Comment(13)
To make it full transparent background, set opacity to 0. Let me know if you have any question about the answer :)Hilly
I will try it in the next few hours when I find the time and will make a reply with the results. Thank you very much.Igenia
You are welcome and Thank you for your feedback :) The screenshot has taken from the execution and it worked properly here.Hilly
I'm a noob so this was a little bit over my head. The way I implemented your solution didn't work well. I know that I need to call Invalidate() on the TransparentLabel every time background changes but I'm a little bit lost since this is all new to me. I've been using link dot-net-transition to experiment and learn about animations and implementing your solution in this sample project link was as described. The last link is the sample project so you can see what mean.Igenia
You should test the answer in a simple test case, for example programmatically using a Timer change the position and BackGround of the PictureBox and you will see the solution work properly. And then you can try to apply the answer to your project.Hilly
I know that it works well. Your solution is awesome. The problem is the transition library that I'm using is confusing for me and cant find a way to call Invalidate() inside its moving function. Link is in the previous comment. linkIgenia
@Igenia thank you for your kind feedback. For a simple test, I made those pictire boxes public and then in the form, I subscribed for PositionChaged event of them and callled ` this.transparentLabel1.Invalidate();` and it worked properly.Hilly
But it's better to subscribe for the event of both picture boxes in the user control and when you received the LocationChanged raise a new custom event and subscribe for this event on your form and put invalidate code there.Hilly
Let us continue this discussion in chat.Igenia
Works perfectly. Thank you.Igenia
I updated onpaint method a bit. You also may find this post helpful: How to make two transparent layer with c#?Hilly
This answer has been here for 9 years, Why Microsoft did not integrate this class in .Net framework already?Sept
@Sept Well, WinForms doesn't support opacity for child controls. So this implementation is just a hack. If you extensively have such requirements, you may want to use WPF or other frameworks.Hilly

© 2022 - 2024 — McMap. All rights reserved.