使用带透明度的Graphics.DrawImage时C#闪烁

时间:2014-05-03 05:21:30

标签: c# graphics transparency gdi+

使用graphics.Drawimage绘制特定的动画GIF图像时出现闪烁问题。我已经用我的程序编写了一个带有代码片段的小程序,以准确显示我想要完成的内容,即直接在桌面上显示透明动画图像,并且可以接受鼠标点击等事件处理程序。

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();
        }
    }
}
}

一切似乎都很好,但如果我尝试添加任何双重缓冲,就会出现很多问题。

1 个答案:

答案 0 :(得分:1)

我设法找到了自己问题的答案。

我将this.DoubleBuffered = true;添加到TransparentForm并添加了公共覆盖,如下所示:

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

不要问我为什么0x0200x0200不起作用,而是覆盖CreateParams与CreateParams结合使用TransparentControl双缓冲区,并且不会让图像闪烁并保持所有透明度。

此解决方案可在此处找到:How to fix the flickering in User controls