您可以使用
分层窗口(Layered Windows):
对于具有复杂形状、动态形状或希望使用 alpha 混合效果的窗口,使用分层窗口可以显著提高性能和视觉效果。系统会自动组合和重绘分层窗口及其底层应用程序的窗口。因此,分层窗口可以平滑地呈现,而不会出现典型的复杂窗口区域闪烁。此外,分层窗口可以部分透明,即 alpha 混合。
在 Windows Forms 中创建分层窗口
以下是来自
msdn 代码库的一些代码,演示如何在 Windows Forms 中创建分层窗口。它允许您创建一个有形状的启动屏幕,并通过鼠标移动它。
将
PerPixelAlphaForm
添加到项目中,然后只需从该表单进行继承并调用其
SelectBitmap
方法,并将您的 png 传递给该方法以创建分层窗口。
PerPixelAlphaForm.cs
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
#endregion
namespace CSWinFormLayeredWindow
{
public partial class PerPixelAlphaForm : Form
{
public PerPixelAlphaForm()
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Load += PerPixelAlphaForm_Load;
}
void PerPixelAlphaForm_Load(object sender, EventArgs e)
{
this.TopMost = true;
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if(!DesignMode)
createParams.ExStyle |= WS_EX_LAYERED;
return createParams;
}
}
protected override void WndProc(ref Message message)
{
if (message.Msg == WM_NCHITTEST)
{
message.Result = (IntPtr)HTCAPTION;
}
else
{
base.WndProc(ref message);
}
}
public void SelectBitmap(Bitmap bitmap)
{
SelectBitmap(bitmap, 255);
}
public void SelectBitmap(Bitmap bitmap, int opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
{
throw new ApplicationException("The bitmap must be 32bpp with alpha-channel.");
}
IntPtr screenDc = GetDC(IntPtr.Zero);
IntPtr memDc = CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr hOldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
hOldBitmap = SelectObject(memDc, hBitmap);
Size newSize = new Size(bitmap.Width, bitmap.Height);
Point sourceLocation = new Point(0, 0);
Point newLocation = new Point(this.Left, this.Top);
BLENDFUNCTION blend = new BLENDFUNCTION();
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = (byte)opacity;
blend.AlphaFormat = AC_SRC_ALPHA;
UpdateLayeredWindow(
this.Handle,
screenDc,
ref newLocation,
ref newSize,
memDc,
ref sourceLocation,
0,
ref blend,
ULW_ALPHA
);
}
finally
{
ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
SelectObject(memDc, hOldBitmap);
DeleteObject(hBitmap);
}
DeleteDC(memDc);
}
}
#region Native Methods and Structures
const Int32 WS_EX_LAYERED = 0x80000;
const Int32 HTCAPTION = 0x02;
const Int32 WM_NCHITTEST = 0x84;
const Int32 ULW_ALPHA = 0x02;
const byte AC_SRC_OVER = 0x00;
const byte AC_SRC_ALPHA = 0x01;
[StructLayout(LayoutKind.Sequential)]
struct Point
{
public Int32 x;
public Int32 y;
public Point(Int32 x, Int32 y)
{ this.x = x; this.y = y; }
}
[StructLayout(LayoutKind.Sequential)]
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)]
struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
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", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteObject(IntPtr hObject);
#endregion
}
}
SplashScreen.cs
public partial class Form4 : CSWinFormLayeredWindow.PerPixelAlphaForm
{
public Form4()
{
InitializeComponent();
this.SelectBitmap(Properties.Resources.splash);
}
}
注意
原始答案基于关闭双缓冲并覆盖OnPaintBackground
,在不调用基本方法的情况下绘制图像。该答案存在已知问题;当窗体静止时它能正常工作,但如果窗体移动或窗口背景改变,则窗口不会更新。您可以在修订版本中查看以前的代码。当前编辑完全基于MSDN代码,没有任何已知问题。