Skinned form with black flicker while resizing! (solution attached)

Nazgulled

Centurion
Joined
Jun 1, 2004
Messages
119
Hi,
I'm trying to create some skinned forms (just the border and caption) with a different approach than you usually see but I'm having some issues with form flickering while I re size the form.

I don't know how else to explain the problem, so here's a video I created of the problem:
http://screencast.com/t/iDv7mPEi0XY

Also, here's a VS2008 test solution with the whole code that repaints the form borders:
http://stuff.nazgulled.net/misc/TestForm.zip

Hope someone can help me getting rid of the flicker...
 
Looking at the code there doesn't seem to be any reason why you should get the flicker...

The only thing that immediately springs to mind is the possibility that the built in double buffering isn't helping; it might be worth looking at buffering it yourself.

Couple of quick changes to try...

C#:
//In the constructor set the styles to
SetStyle(ControlStyles.ResizeRedraw, true);

also modified the actual painting to be
C#:
protected override void OnPaintBackground(PaintEventArgs e) {
           // base.OnPaintBackground(e);
            BufferedGraphics g;
            BufferedGraphicsContext context = BufferedGraphicsManager.Current;
            context.MaximumBuffer= new Size(Width, Height);

            g = context.Allocate(e.Graphics, new Rectangle(0, 0, Width, Height));

            FormRegions.Left = new Rectangle(0, 6, 5, ClientSize.Height - 12);
            FormRegions.Right = new Rectangle(ClientSize.Width - 5, 6, 5, ClientSize.Height - 12);
            FormRegions.Top = new Rectangle(6, 0, ClientSize.Width - 12, 5);
            FormRegions.TopLeft = new Rectangle(0, 0, 6, 6);
            FormRegions.TopRight = new Rectangle(ClientSize.Width - 6, 0, 6, 6);
            FormRegions.Bottom = new Rectangle(6, ClientSize.Height - 5, ClientSize.Width - 12, 5);
            FormRegions.BottomLeft = new Rectangle(0, ClientSize.Height - 6, 6, 6);
            FormRegions.BottomRight = new Rectangle(ClientSize.Width - 6, ClientSize.Height - 6, 6, 6);
            FormRegions.Caption = new Rectangle(5, 5, ClientSize.Width - 10, SkinImage.Caption.Height);
            FormRegions.Background = new Rectangle(5, 5, ClientSize.Width - 10, ClientSize.Height - 10);

            g.Graphics.FillRectangle(Brushes.White, FormRegions.Background);

            g.Graphics.DrawImage(SkinImage.Caption, FormRegions.Caption, 0, 0,
                                 SkinImage.Caption.Width, SkinImage.Caption.Height,
                                 GraphicsUnit.Pixel, SkinAttributes);
            g.Graphics.DrawImage(SkinImage.CaptionLeft, 5, 5,
                                 SkinImage.CaptionLeft.Width, SkinImage.CaptionLeft.Height);
            g.Graphics.DrawImage(SkinImage.CaptionRight, FormRegions.Caption.Width + 4, 5,
                                 SkinImage.CaptionRight.Width, SkinImage.CaptionRight.Height);

            g.Graphics.DrawImage(SkinImage.Left, FormRegions.Left, 0, 0, SkinImage.Left.Width,
                                 SkinImage.Left.Height, GraphicsUnit.Pixel, SkinAttributes);
            g.Graphics.DrawImage(SkinImage.Right, FormRegions.Right, 0, 0, SkinImage.Right.Width,
                                 SkinImage.Right.Height, GraphicsUnit.Pixel, SkinAttributes);
            g.Graphics.DrawImage(SkinImage.Top, FormRegions.Top, 0, 0, SkinImage.Top.Width,
                                 SkinImage.Top.Height, GraphicsUnit.Pixel, SkinAttributes);
            g.Graphics.DrawImage(SkinImage.TopLeft, FormRegions.TopLeft);
            g.Graphics.DrawImage(SkinImage.TopRight, FormRegions.TopRight);
            g.Graphics.DrawImage(SkinImage.Bottom, FormRegions.Bottom, 0, 0,
                                 SkinImage.Bottom.Width, SkinImage.Bottom.Height,
                                 GraphicsUnit.Pixel, SkinAttributes);
            g.Graphics.DrawImage(SkinImage.BottomLeft, FormRegions.BottomLeft);
            g.Graphics.DrawImage(SkinImage.BottomRight, FormRegions.BottomRight);

            g.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            g.Graphics.DrawString(Text, new Font(Font.Name, 15, Font.Style), Brushes.Black, new PointF(47, 11));

            g.Render(e.Graphics);
        }

seems to make things better but certainly isn't perfect ;) might be a useful starting point though...
 
I'll try that when I get the chance, question though... Why don't you call "base.OnPaintBackground(e);" at all? Either in the beginning or end of the method?

EDIT:
Just tried your code and I'm not sure it helped, at least my eye can't notice much of a difference... And it presented a new problem. The example I gave is a perfectly squared form, however, I tried with non-square example and with your code a black background would appear on the transparent parts...
 
Last edited:
It seemed to have less of a flicker on my computer :( oh well.

If you are handling the OnPaintBackground then you don't need to call the base as you are normally completely changing how the form is erased anyway.

Have you tried drawing the border in the normal OnPaint handler rather than in OnPaintBackground to see if that makes any difference in appearance?
 
Have you tried drawing the border in the normal OnPaint handler rather than in OnPaintBackground to see if that makes any difference in appearance?
Using your code or mine? I think I tried with my version but it was the same, maybe yours will be better if I use it on the OnPaint event?
 
Playing around with it a bit here and nothing seems to make much of a difference.

Probably the best so far is handling all drawing in the OnPaint method and explicitly ignoring the request to clear the background (handle WM_ERASEBKGND in your WndProc and bail without doing anything).

I still can't remove the flicker though and it is getting annoying ;) Oddly enough specifying the ControlStyles.AllPaintingInWmPaint style seems to make it worse despite the fact all drawing is being done in the Paint event.

Out of interest what OS are you running on? Vista 32 bit with a Nvidia card here...
 
Why do you specify a transparency key? Is this to support irregular shapes? The reason I ask is that I changed the constructor in skinnedForm.cs to...
C# Code[HorizontalRule]magic hidden text[/HorizontalRule]············BackColor = SystemColors.Control;
············FormBorderStyle = FormBorderStyle.None;
············//TransparencyKey = Color.Lime;
[HorizontalRule]Why are you quoting me?[/HorizontalRule]
The important thing is the third line. This seemed to solve the problem. It might be related to layered windows. Or it might not. I'm not sure how DotNet implements the transparency key.

[Edit]P.S. I tried running the app with no transparency key and with partial opacity and the ugly blackness came back. It looks like layered windows combined with the way that DotNet does its painting and its double buffering could be the culprit.[/Edit]
 
@PlausiblyDamp
Vista 32bits with ATi card (mobility)

@marble_eater
Yes, it's supposed to support irregular shapes that's why the transparency key is there... but I don't think the transparency key has anything to do with layered windows...
 
From what I can tell, the TransparencyKey is implemented using layered windows.

I can't find any documentation that says so, but this page makes that claim, and it would be a reasonable explaination for why the program exhibits the same symptoms using semitranparency as when using a TransparencyKey. Also, seeing as this article states that TransparencyKey only works on Windows 2000 and later (when layered windows were introduced) and that I can't think of another reasonable way in which the TransparencyKey could be implemented, I would guess that that's how it's implemented.
 
You may be right... :) But how does that help us/me fix the problem?

Whenever I get the chance (dunno when cause I'm full of university work and exams) I'll try a couple of things and post the results but if anyone has any more suggestions...
 
One option would be to use regions to (re)implement the transparency key yourself while avoiding using layered windows.
 
Could you be a little more specific on that? And/or provide a little example/sample?

What exactly do you mean by "regions" and how would that avoid using layered windows?
 
Back
Top