Click here to Skip to main content
15,900,725 members
Please Sign up or sign in to vote.
3.67/5 (4 votes)
See more:
***
I have solved this solution with an idea I thought up myself. I have posted the solution I used below.
***


Hello everyone,

I am having an issue with transparent child members causing a flicker over their parent's GradientBrushed background image. I would like to remove this flickering completely and am unsure how to make that happen.

I am setting a Panel's background image to a bitmap painted with a LinearGradientBrush when the MouseEnter event of the Panel fires, and back to transparent once the MouseLeave event fires.

***
Edit -
I forgot to mention that I have tried surrounding the call to the drawing method with .SuspendLayout() and .ResumeLayout() for the Panel and each of the corresponding transparent child members.
***
I have set double buffering and AllPaintingInWmPaint to true for the main form:

MIDL
// Style
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);


The following is how I am painting the gradient to the Panel which houses the transparent Labels:

C#
System.Drawing.Drawing2D.LinearGradientBrush gradBrush;
            gradBrush = new System.Drawing.Drawing2D.LinearGradientBrush(
                new Rectangle { Height = panel.Height, Width = panel.Width }, Color.FromArgb(90, Color.DodgerBlue), Color.White, LinearGradientMode.Vertical);
            Bitmap bmp = new Bitmap(panel.Width, panel.Height);

            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(gradBrush, new Rectangle(0, 0, panel.Width, panel.Height));
            panel.BackgroundImage = bmp;
            panel.BackgroundImageLayout = ImageLayout.Stretch;


Is there something I need to set for each Label that the Panel has as a child to get the flicker to go away?

Here is a screen shot I have taken which catches the flicker in action as I move my mouse up and down over the panels very quickly:

http://i53.tinypic.com/2vb4wp0.png[^]
Posted
Updated 25-Mar-11 6:09am
v3
Comments
Albin Abel 16-Mar-11 15:12pm    
Ok you have set buffering already. I deleted my answer
Sergey Alexandrovich Kryukov 17-Mar-11 1:37am    
I think your answer was actually correct: OP did the trick, but not where it should be done.
Sorry man, you deleted it too early :-)
--SA
Albin Abel 16-Mar-11 15:19pm    
I hope you have disposing the bmp created and the Graphics g in the later part of the code. Also may be try drawing the bitmap instead of setting it as background. As John said if the same bmp has to use again and again then created it one time and store it and use again and again. Hope that helps
Sergey Alexandrovich Kryukov 16-Mar-11 20:55pm    
You should also explain on what operation the flicker occurs. You've done all general remedies, it leaves for specific one.
--SA
Josh Machol 16-Mar-11 22:32pm    
I'm sorry, SA, I'm confused by what you mean? Is the MouseEnter or MouseLeave event not when it is occurring?

OK, based on the clarifications by OP pulled over a considerable amount of time and between long and fruitful discussions on the topic of proper member behavior :-) I've found at least one big fault which certainly should cause strong flickering.

The major way of of fighting flicker is Double Buffering. As the flicker-prone rendering was detected on some control of the type Panel, it is important, that Double Buffering is applied to that control. Using this remedy on the parent Form would not effect flicker on the child control in any way.

To improve the situation, a custom Control should be used. A base class can be Panel, but proper base class is Control. The custom control should set up the anti-flicker property in its constructor:

C#
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);


(Same styles were set for the Form but did not serve the purpose.)

Any other control which causes or can potentially cause flicker should be build in a similar way.

Disclaimer: I cannot take responsibility for any other source of flicker or any other unwanted effects created by the OP code which I am not aware of.

OP is recommended to prefer logical and rational considerations instead of the approach of cook-book recipe. :-)

—SA
 
Share this answer
 
v2
Comments
Albin Abel 17-Mar-11 1:44am    
Hmm. you are good detective. I haven't noticed he double buffer only the form. I want to give a 100, but code project not allows that. so 5 :(
Sergey Alexandrovich Kryukov 17-Mar-11 1:52am    
Oh, thank you a lot. You're too nice.
Let's see what Josh say, he must be testing...
--SA
Josh Machol 17-Mar-11 9:50am    
Who knew that a day was a "considerable amount of time." Exaggerative much? Thank you for the clarification that enabling ControlStyles on a parent form has no affect on its child forms. I had been misinformed about that.

I am creating the custom controls now.

***
Edit -
It is possible that I may have implemented this solution incorrectly; however, I have performed this solution before to other controls with no issue. Creating custom controls which enable double buffering in their constructors did not fix the solution.

I can't help but feel that this issue is because of how Microsoft is handling transparency. The Panel's background is painted first, and then the Label's background is updated afterwards. I think that both of these actions are being performed in a double buffered way, but at separate times.
Sergey Alexandrovich Kryukov 17-Mar-11 13:15pm    
Do you have a sense of humor only if you're making fun of someone, not the other way around? :-)

OK, I did not understand from your response if your flicker is gone or not? Or you need time to finally give it a try? Please reply.

The transparency... It depend on what kind of transparency do you mean. If this is about GDI+ transparency using alpha channel in colors, it works quite fine. If this is a transparency property of the Window, it was quite ugly and I never knew if it was dramatically improved, ever (do you use it?). Therefore, I always recommend implementing transparency in rendering and avoid transparency properties.

By the way, I'm curious to know, is it your vote of "3" here? Again, not that I care, but interested to know your opinion...

--SA
Espen Harlinn 17-Mar-11 15:44pm    
Good effort, my 5
0) Create the background image one time, and use that pre-created image for the background. The flickering is probably being seen because the form is redrawing the gradient each tim.

EDIT ================

1) Try surrounding the drawing code with SuspendLayout() and ResumeLayout().

EDIT ================

2) Try this version of SetStyle:

C#
SetStyle(ControlStyles.SupportsTransparentBackColor | 
         ControlStyles.Opaque | 
         ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint, true);


EDIT ================

3) Try putting the labels into their own transparent panel.

4) Try painting to a bitmap and putting that *under* the panel holding the labels
 
Share this answer
 
v5
Comments
Josh Machol 16-Mar-11 14:53pm    
Thank you for the suggestion; however, that does not fix the issue.
#realJSOP 16-Mar-11 15:02pm    
That doesn't mean you have to vote my answer a 1. I took the time to try to provide a solution, and a 1 vote won't convince me I should continue trying to help.
Josh Machol 16-Mar-11 15:04pm    
I am sorry that you feel so strongly about me voting your solution that failed to fix my issue as a 1. I hope in the future you may wish you continue to help others after they do so.

Thanks for the suggested solution none-the-less!
#realJSOP 16-Mar-11 15:10pm    
I think you misunderstand. I see no reason to keep trying to help *you*. You probably haven't told us everything you've tried, so we have to divine from thin freakin' air what to offer as help.
Josh Machol 16-Mar-11 15:12pm    
That is great news. I am curious to see what your reason was in the first place. If your reason was to obtain a high vote on your solution, I would suggest going back to the drawing board to take a look at why you help people.
Hello Self,

I believe I have a great solution for you, and it is as follows:

Instead of using Labels to display the text, which require a Color.Transparent background to allow for the Panel's background to show through, simple create a custom control which extends the System.Windows.Forms.Panel class and override the OnPaint method and paint the desired text directly to the custom Panel.

***Be sure to get the exact points for where you want the Text to begin, and the Font you wish to use beforehand.

Here is an example of how I wrote it:

XML
public partial class OpenNewPanel : System.Windows.Forms.Panel
{
    #region Members

    private const float TITLE_POINT_SIZE = 16;
    private const float DESCRIPTION_POINT_SIZE = 9;

    private Bitmap gradientBackground { get; set; }
    private Point titleLocation = new Point(156, 4);
    private Point descriptionLocation = new Point(161, 30);

    public string PanelTitle { get; set; }
    public string PanelDescription { get; set; }

    #endregion // Members

    /// <summary>
    /// Ctor
    /// </summary>
    public OpenNewPanel()
    {
        InitializeComponent();
        // Members
        this.PanelTitle = string.Empty;
        this.PanelDescription = string.Empty;
        // Styles
        SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
        // Misc
        InitializeBackgroundGradient();
        // Events
        this.MouseEnter += new EventHandler(OpenNewPanel_MouseEnter);
        this.MouseLeave += new EventHandler(OpenNewPanel_MouseLeave);
    }

    #region Overrides

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        //
        // --- Custom Paint Operations Below ---
        //
        //e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
        Graphics graphics = e.Graphics;
        Font titleFont = new Font("Microsoft Sans Serif", TITLE_POINT_SIZE , FontStyle.Bold, GraphicsUnit.Point);
        Font descriptionFont = new Font("Microsoft Sans Serif", DESCRIPTION_POINT_SIZE , FontStyle.Regular, GraphicsUnit.Point);
        StringFormat format = new StringFormat();
        format.Alignment = StringAlignment.Near;

        this.SuspendLayout();
        this.InvokePaintBackground(this, e);
        // Draw Title
        graphics.DrawString(this.PanelTitle, titleFont, new SolidBrush(Color.Black), (PointF)this.titleLocation);
        // Draw Description
        graphics.DrawString(this.PanelDescription, descriptionFont, Brushes.Black,
            new RectangleF(this.descriptionLocation.X, this.descriptionLocation.Y, this.Width - this.descriptionLocation.X - 10, this.descriptionLocation.Y + 100),
            format);
        this.ResumeLayout();
    }

    #endregion // Overrides

    #region Events

    /// <summary>
    /// Fires when the mouse enters the Open New Panel
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OpenNewPanel_MouseEnter(object sender, EventArgs e)
    {
        SuspendLayout();
        this.BackgroundImage = this.gradientBackground;
        this.BackColor = Color.Transparent;
        ResumeLayout();
    }

    /// <summary>
    /// Fires when the mouse leaves the Open New Panel
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OpenNewPanel_MouseLeave(object sender, EventArgs e)
    {
        SuspendLayout();
        this.BackgroundImage = null;
        this.BackColor = Color.Transparent;
        ResumeLayout();
    }

    #endregion // Events

    #region Methods

    /// <summary>
    /// Creates a Vertical DodgerBlue to White Gradient Bitmap
    /// </summary>
    private void InitializeBackgroundGradient()
    {
        System.Drawing.Drawing2D.LinearGradientBrush gradBrush;
        gradBrush = new System.Drawing.Drawing2D.LinearGradientBrush(
            new Rectangle { Height = this.Height, Width = this.Width }, Color.FromArgb(90, Color.DodgerBlue), Color.White, LinearGradientMode.Vertical);
        Bitmap bmp = new Bitmap(this.Width, this.Height);
        Graphics g = Graphics.FromImage(bmp);
        g.FillRectangle(gradBrush, new Rectangle(0, 0, this.Width, this.Height));
        this.gradientBackground = bmp;
    }

    #endregion // Methods
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900