如何在.NET中重现Firefox褪色的图像/文本拖动效果?

时间:2009-11-17 20:11:53

标签: .net firefox drag-and-drop

好的,我知道这可能是一个非常新的问题,但是当谈到图形编程时,我一个新的:)

Firefox如何在显示所选图像或文本的漂亮褪色副本时实现拖放效果?请参阅下面的SO徽标示例。

另外,我怎样才能在C#/ VB.NET中重现这种效果? (最好是WinForms,因为我还不知道WPF。)

我还注意到“淡入淡出”的来源是基于图像中的光标位置(继续,现在试试,你会看到我的意思!)

我想我可以深入研究来源over at MDC,但我认为这里有人可能已经熟悉这种技术了。

Firefox drag & drop

1 个答案:

答案 0 :(得分:1)

我会在鼠标左右的鼠标位置创建一个新的Layered Window。新窗口将从所需内容(图像或文本)中获取内容,该内容将使用Alpha通道进行渲染,该通道随着远离鼠标移动而减少。

将文本或图像渲染为带有Alpha通道的GDI +位图,循环显示像素并将Alpha通道设置为鼠标光标位置的函数。在分层窗口上设置位图,并根据鼠标的位置更新它的位置。

在C#中创建一个分层窗口(取自其他一些来源):

    public class SplashScreenForm : Form
{

    public SplashScreenForm()
    {

        this.TopMost = true;
        this.Show();
        SelectBitmap(Properties.Resources.splashblended);
    }

    // Sets the current bitmap
    public void SelectBitmap(Bitmap bitmap) 
    {
        // Does this bitmap contain an alpha channel?
        if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
        {
            throw new ApplicationException("The bitmap must be 32bpp with alpha-channel.");
        }

        // Get device contexts
        IntPtr screenDc = APIHelp.GetDC(IntPtr.Zero);
        IntPtr memDc = APIHelp.CreateCompatibleDC(screenDc);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr hOldBitmap = IntPtr.Zero;

        try 
        {
            // Get handle to the new bitmap and select it into the current device context
            hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
            hOldBitmap = APIHelp.SelectObject(memDc, hBitmap);

            // Set parameters for layered window update
            APIHelp.Size newSize = new APIHelp.Size(bitmap.Width, bitmap.Height);   // Size window to match bitmap
            APIHelp.Point sourceLocation = new APIHelp.Point(0, 0);
            APIHelp.Point newLocation = new APIHelp.Point(this.Left, this.Top);     // Same as this window
            APIHelp.BLENDFUNCTION blend = new APIHelp.BLENDFUNCTION();
            blend.BlendOp             = APIHelp.AC_SRC_OVER;                        // Only works with a 32bpp bitmap
            blend.BlendFlags          = 0;                                          // Always 0
            blend.SourceConstantAlpha = 255;                                        // Set to 255 for per-pixel alpha values
            blend.AlphaFormat         = APIHelp.AC_SRC_ALPHA;                       // Only works when the bitmap contains an alpha channel

            // Update the window
            APIHelp.UpdateLayeredWindow(Handle, screenDc, ref newLocation, ref newSize,
                memDc, ref sourceLocation, 0, ref blend, APIHelp.ULW_ALPHA);
        }
        finally 
        {
            // Release device context
            APIHelp.ReleaseDC(IntPtr.Zero, screenDc);
            if (hBitmap != IntPtr.Zero) 
            {
                APIHelp.SelectObject(memDc, hOldBitmap);
                APIHelp.DeleteObject(hBitmap);                                      // Remove bitmap resources
            }
            APIHelp.DeleteDC(memDc);
        }
    }

    protected override CreateParams CreateParams    
    {
        get 
        {
            // Add the layered extended style (WS_EX_LAYERED) to this window
            CreateParams createParams = base.CreateParams;
            createParams.ExStyle |= APIHelp.WS_EX_LAYERED;
            return createParams;
        }
    }
}

// Class to assist with Win32 API calls
internal class APIHelp 
{
    // Required constants
    public const Int32  WS_EX_LAYERED   = 0x80000;
    public const Int32  HTCAPTION       = 0x02;
    public const Int32  WM_NCHITTEST    = 0x84;
    public const Int32  ULW_ALPHA       = 0x02;
    public const byte   AC_SRC_OVER     = 0x00;
    public const byte   AC_SRC_ALPHA    = 0x01;

    public enum Bool 
    {
        False = 0,
        True = 1
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Point 
    {
        public Int32 x;
        public Int32 y;

        public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Size 
    {
        public Int32 cx;
        public Int32 cy;

        public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct ARGB 
    {
        public byte Blue;
        public byte Green;
        public byte Red;
        public byte Alpha;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct BLENDFUNCTION 
    {
        public byte BlendOp;
        public byte BlendFlags;
        public byte SourceConstantAlpha;
        public byte AlphaFormat;
    }

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("user32.dll", ExactSpelling = true)]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteDC(IntPtr hdc);

    [DllImport("gdi32.dll", ExactSpelling = true)]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteObject(IntPtr hObject);
}