1

I am having a flickering problem when drawing specific animated GIF images using graphics.Drawimage. I have written a small program with snippets of code from my program to show exactly what I'm trying to accomplish, which is to display a transparent animated image directly on the desktop and can accept event handlers such as mouse clicks.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;

namespace Transparancy_Example
{
    class TransparentForm : System.Windows.Forms.Form
    {
        public TransparentForm()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        UpdateStyles();
        this.TopMost = true;
        this.FormBorderStyle = FormBorderStyle.None;
        this.ShowInTaskbar = false;
        this.AllowTransparency = true;
        this.StartPosition = FormStartPosition.CenterScreen;
        TransparentControl tc = new TransparentControl();
        tc.Parent = this;
        tc.Dock = DockStyle.Fill;
        tc.BackColor = Color.Transparent;
        tc.Image = Properties.Resources.animated_gif;
        this.Controls.Add(tc);
        this.Size = tc.Image.Size;
        this.SetBounds(0, 0, Width, Height);
        Bitmap bmp = new Bitmap(tc.Image);
        Color makeColorTransparent = bmp.GetPixel(0, 0);
        if (bmp.PixelFormat != PixelFormat.Format32bppArgb && makeColorTransparent.A != Color.Transparent.A)
        {
            this.TransparencyKey = bmp.GetPixel(0, 0);
        }
        else if (makeColorTransparent.A != Color.Transparent.A)
        {
            this.TransparencyKey = bmp.GetPixel(0, 0);
        }
        else
        {
            this.TransparencyKey = this.BackColor;
        }
    }
}
public class TransparentControl : Control
{
    private readonly Timer refresher;
    private Image _image;

    public TransparentControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        UpdateStyles();

        BackColor = Color.Transparent;
        refresher = new Timer();
        refresher.Tick += TimerOnTick;
        refresher.Interval = 50;
        refresher.Enabled = true;
        refresher.Start();
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x020;
            return cp;
        }
    }

    protected override void OnMove(EventArgs e)
    {
        RecreateHandle();

    }

    protected override void OnPaint(PaintEventArgs e)
    {
        if (_image != null)
        {

            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            double ratioX = (double)Width / (double)_image.Width;
            double ratioY = (double)Height / (double)_image.Height;
            double ratio = ratioX < ratioY ? ratioX : ratioY;
            int newHeight = Convert.ToInt32((double)_image.Height * ratio);
            int newWidth = Convert.ToInt32((double)_image.Width * ratio);
            int posX = Convert.ToInt32((Width - ((double)_image.Width * ratio)) / 2);
            int posY = Convert.ToInt32((Height - ((double)_image.Height * ratio)) / 2);

            e.Graphics.DrawImage(_image, posX, posY, newWidth, newHeight);
            ImageAnimator.UpdateFrames(_image);

        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        //Do not paint background
    }

    public void Redraw()
    {
        RecreateHandle();
    }

    private void TimerOnTick(object source, EventArgs e)
    {
        RecreateHandle();
        refresher.Stop();
        ImageAnimator.Animate(_image, onFrameChangedHandler);

    }

    private void onFrameChangedHandler(object sender, EventArgs e)
    {
        if (Parent != null)
        {
            this.Parent.Invalidate(this.Bounds, false);
        }
    }

    public Image Image
    {
        get
        {
            return _image;
        }
        set
        {
            _image = value;
            RecreateHandle();
        }
    }
}
}

Everything seems fine, but if I try to add any doublebuffering, LOTS of problems occur.

MrFreeman
  • 47
  • 7
  • Have you enabled DoubleBuffering=True in the form property ? – techno May 04 '14 at 10:17
  • 1
    I did add `this.DoubleBuffered = true;` to the Form, but it did not seem to have any affect. It could be that the animation is just tearing for some reason and it may not be a buffering issue? – MrFreeman May 04 '14 at 17:25

1 Answers1

1

I managed to find the answer to my own question.

I added this.DoubleBuffered = true; to the TransparentForm and added the public override as follows:

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

Do not ask me why 0x020 or 0x0200 does not work, but that overrride CreateParams combined with the CreateParams with the TransparentControl double buffers and does not let the image flicker and keeps all transparency.

This solution was found here: How to fix the flickering in User controls

Community
  • 1
  • 1
MrFreeman
  • 47
  • 7
  • Those other random numbers don't work because they don't correspond to the `WS_EX_COMPOSITED` extended window style. `0x02000000` is the correct value for this constant. The documentation is available [here](http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543.aspx). (You might also consider [edit]ing this answer to give credit to wherever you found your answer.) – Cody Gray - on strike May 07 '14 at 05:48
  • I'll be sure to add the credit, but adding `0x02000000` to the TransparentControl breaks transparency... – MrFreeman May 07 '14 at 18:29