2 c# customization transparency winforms
我有一个窗体形式的图像集合,并希望使它们"非矩形" - 即透明背景.
但是,使用时transparencyKey,是的,都会松开背景颜色.但是,在任何时候我都只能看到一个而不是另一个(取决于哪个是'带到前面').
有没有办法在表格上显示两个图像,都是"非矩形",两者都有透明背景?
请注意:我设法让背景变得透明(TransparencyKey设置为a gray (RGB of 66,66,66),两个图像都具有相同的背景.
我听说过' regions' 这个术语,但从我所知道的情况来看,这通常是CPU上非常'重'的方式.
任何建议都非常感谢并乐于回答任何澄清问题(因为我不太擅长解释自己).
注意.我试图实现的"效果"类似于项目启动时开启的X战警门 - 我的桌面就在后面.

此尝试使用UpdateLayeredWindow API:http://msdn.microsoft.com/en-us/library/ms997507.aspx#layerwin_topic2a
我从Corylulu激发了我的实现:https://stackoverflow.com/a/8809657/1812199
这两个位图是动态创建的,但您可以从文件系统或其他任何位置加载它们.
叠加窗口当前遍布整个主屏幕,但您也可以选择将表单的位置和大小设置为您需要的任何内容(例如,在另一个表单的顶部).
我为这两个位图实现了一个非常基本的动画,但是你要比我更有创意:)
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace StackOverflow25400312
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var bounds = Screen.PrimaryScreen.Bounds;
var imagesSize = new Size(bounds.Width * 2 / 3, bounds.Height);
var left = LoadLeftDoorTransparentPng(imagesSize);
var right = LoadRightDoorTransparentPng(imagesSize);
// Create a form with same dimension as the screen.
var form = new OverlayForm(left, right, bounds);
Application.Run(form);
}
private static Image GenerateImage(GraphicsPath path, Size sz)
{
var bitmap = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb);
var graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.Transparent);
graphics.FillPath(Brushes.Red, path);
return bitmap;
}
private static Image LoadRightDoorTransparentPng(Size sz)
{
int w = sz.Width;
int h = sz.Height;
var path = new GraphicsPath();
path.AddLines(new[]
{
new Point(w / 2, 0),
new Point(w, 0),
new Point(w, h),
new Point(w / 2, h),
new Point(0, h / 2),
});
// I will generate it by code but you should use Bitmap.FromFile(...)
return GenerateImage(path, sz);
}
private static Image LoadLeftDoorTransparentPng(Size sz)
{
int w = sz.Width;
int h = sz.Height;
var path = new GraphicsPath();
path.AddLines(new[]
{
new Point(0, 0),
new Point(w, 0),
new Point(w / 2, h / 2),
new Point(w, h),
new Point(0, h),
});
// I will generate it by code but you should use Bitmap.FromFile(...)
return GenerateImage(path, sz);
}
}
public class OverlayForm : Form
{
public const int WS_EX_NOACTIVATE = 0x08000000;
public const int WS_EX_TOOLWINDOW = 0x00000080;
public const int WS_EX_TOPMOST = 0x00000008;
public const int WS_EX_LAYERED = 0x00080000;
public const int WS_EX_TRANSPARENT = 0x00000020;
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hdc);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("gdi32.dll", SetLastError = true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("user32.dll")]
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[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 pptSrc, uint crKey,
[In] ref BLENDFUNCTION pblend, uint dwFlags);
public const int ULW_ALPHA = 2;
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{
this.cx = cx;
this.cy = cy;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
public POINT(System.Drawing.Point pt) : this(pt.X, pt.Y) { }
public static implicit operator System.Drawing.Point(POINT p)
{
return new System.Drawing.Point(p.X, p.Y);
}
public static implicit operator POINT(System.Drawing.Point p)
{
return new POINT(p.X, p.Y);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format)
{
BlendOp = op;
BlendFlags = flags;
SourceConstantAlpha = alpha;
AlphaFormat = format;
}
}
public const int AC_SRC_OVER = 0x00;
public const int AC_SRC_ALPHA = 0x01;
private readonly Image _left;
private readonly Image _right;
private readonly Bitmap _backBuffer;
private readonly Timer _timer;
private int _offset;
public OverlayForm(Image left, Image right, Rectangle bounds)
{
_left = left;
_right = right;
_backBuffer = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
_timer = new Timer();
_offset = 0;
Bounds = bounds;
FormBorderStyle = FormBorderStyle.None;
StartPosition = FormStartPosition.Manual;
ShowInTaskbar = false;
}
protected override bool ShowWithoutActivation
{
get { return true; }
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_LAYERED; // This form has to have the WS_EX_LAYERED extended style
cp.ExStyle |= WS_EX_TRANSPARENT; // Click through.
cp.ExStyle |= WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
return cp;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_timer.Interval = 16;
_timer.Tick += _timer_Tick;
_timer.Start();
}
private void UpdateLayeredWindow()
{
using (Graphics g = Graphics.FromImage(_backBuffer))
{
g.Clear(Color.Transparent);
g.DrawImage(_left, 0 - _offset, 0);
g.DrawImage(_right, Width - _right.Width + _offset, 0);
SetBitmap(_backBuffer);
}
}
private void SetBitmap(Bitmap bitmap)
{
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = GetDC(IntPtr.Zero);
IntPtr memDc = CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
oldBitmap = SelectObject(memDc, hBitmap);
SIZE size = new SIZE(bitmap.Width, bitmap.Height);
POINT pointSource = new POINT(0, 0);
POINT topPos = new POINT(Left, Top);
BLENDFUNCTION blend = new BLENDFUNCTION();
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
bool fail = UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, ULW_ALPHA);
}
finally
{
ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
SelectObject(memDc, oldBitmap);
DeleteObject(hBitmap);
}
DeleteDC(memDc);
}
}
void _timer_Tick(object sender, EventArgs e)
{
int distance = _left.Width - _offset;
// Is animation done?
if (distance == 0)
{
_timer.Stop();
Close();
return;
}
// Step forward.
// You can replace with any easing function of your choice,
// but this one works well usually.
int step = distance / 9;
// Help it a little when the animation is about to end.
if (step == 0)
step = distance;
_offset += step;
UpdateLayeredWindow();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_left.Dispose();
_right.Dispose();
_backBuffer.Dispose();
_timer.Dispose();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)