0

I have a panel and on that I've a picturebox. There are around 20 labels that I've to show in the panel. I want the background of Label to be transparent ie the image in picturebox is shown and the label displays only the text. Now since labels do not exhibit true transparency I made the labels child of picturebox

 this.lbl1.Parent = pictureBox1;

This has solved my immediate problem but now when the form loads, all the labels take a while to become visible and do so one at a time. I'd appreciate if you guys can give some solution for this.

Thanks in advance

Arcturus
  • 437
  • 1
  • 8
  • 19

3 Answers3

4

The standard cure for flicker is double-buffering. But that cannot solve this kind of flicker. It is a different kind, caused by having multiple windows overlapping each other. Each label is its own window. When the form needs to paint itself, it draws its background leaving holes for the child windows. Each child window then takes a turn drawing itself. And their child windows draw themselves next. Etcetera.

This becomes noticeable when one control takes a while to draw, no doubt your picture box. Especially when it displays a large image that needs to be resized. The holes for the child windows stay unpainted while the picture box draws. They have a white background, black when you use the form's TransparencyKey or Opacity property. This can contrast badly with the image in your picture box, that effect is perceived by the user as flicker.

One immediate cure is to not use controls so you don't pay for their window. A Label is very convenient but it is a massive waste of system resources to burn up a window just to display a string. You can simply implement the picture box' Paint event and draw the strings with TextRenderer.DrawText(). PictureBox has double-buffering turned on by default so the image as well as the text is drawn completely smoothly, no more flicker. The obvious disadvantage is that you lose the convenience of point-and-click, you have to write code.

There are other fixes possible. One of them is to prevent the picture box from leaving holes for the child windows. It will draw the entire image, the labels pop on top of them. That's still flicker but not nearly as noticeable. Add a new class to your project and paste this code:

using System;
using System.Windows.Forms;

internal class MyPictureBox : PictureBox {
    protected override CreateParams CreateParams {
        get {
            var parms = base.CreateParams;
            parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
            return parms;
        }
    }
}

Compile and drop the new picture box control from the top of the toolbox onto your form.

Yet another possible workaround is to make the form and all of its children double-buffered. This doesn't speed up the painting at all but all of the windows get rendered into a memory buffer, the result is blitted to the screen. You'll notice a delay but the window suddenly pops on the screen. This is called compositing. Winforms doesn't support this directly since it can have side-effects but it is easy to enable. Paste this code into your form class:

protected override CreateParams CreateParams {
    get {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
} 

Supported by XP and later. Watch out for painting artifacts.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Pretty comprehensive answer. Thanks for taking the time. Double buffering take far too much time to display the form and also mucks up the display of datagrid etc on the form. The custom Picture box solution eliminated the holes issue and the labels came quickly but still.. I think I'd go with the TextRenderer solution. – Arcturus Jul 08 '11 at 13:49
1

or you can ditch the labels and draw the text yourself:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
  TextRenderer.DrawText(e.Graphics, "Label1", SystemFonts.DefaultFont,
                        new Point(10, 10), Color.Black, Color.Empty);
}
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • looks promising! let me try and report back :) – Arcturus Jul 08 '11 at 13:06
  • Works fine for labels whose value won't change but some labels have values that are regularly updated. How would I update the values if I use the TextRenderer inside the paint event? – Arcturus Jul 08 '11 at 13:15
  • @Arcturus call pictureBox.Invalidate() – LarsTech Jul 08 '11 at 13:20
  • pictureBox1.Invalidate() calls Paint event so doing it this way. Thanx Edit: yes Lars just found about it (from another StackOverflow ans actually) – Arcturus Jul 08 '11 at 13:21
0

The label does not support transparency, you must create your own unique custom control, you can see these code examples.

http://www.codeproject.com/KB/dotnet/transparent_controls_net.aspx http://www.codeproject.com/KB/vb/uLabelX.aspx

Bye