使用UpdateLayeredWindow绘图控件的C#透明窗体
我正在开发一个exe,我需要有一个透明的背景。我在Photoshop中制作了这张图片,它包含了所有整洁的东西(阴影/不透明度、反射等) 我一直在努力使用透明色+背景色+背景图像使其正常工作,但我总是以一些像素不透明而告终。因此,我切换到UpdateLayeredWindow,它工作正常,但现在没有绘制任何控件 这是我的一些代码使用UpdateLayeredWindow绘图控件的C#透明窗体,c#,winforms,png,transparent,C#,Winforms,Png,Transparent,我正在开发一个exe,我需要有一个透明的背景。我在Photoshop中制作了这张图片,它包含了所有整洁的东西(阴影/不透明度、反射等) 我一直在努力使用透明色+背景色+背景图像使其正常工作,但我总是以一些像素不透明而告终。因此,我切换到UpdateLayeredWindow,它工作正常,但现在没有绘制任何控件 这是我的一些代码 private void Form1_Load(object sender, EventArgs e) { UpdateFormDispl
private void Form1_Load(object sender, EventArgs e)
{
UpdateFormDisplay(this.BackgroundImage);
}
protected override void OnPaint(PaintEventArgs e)
{
UpdateFormDisplay(this.BackgroundImage);
}
public void UpdateFormDisplay(Image backgroundImage)
{
IntPtr screenDc = API.GetDC(IntPtr.Zero);
IntPtr memDc = API.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
//Display-image
Bitmap bmp = new Bitmap(backgroundImage);
hBitmap = bmp.GetHbitmap(Color.FromArgb(0)); //Set the fact that background is transparent
oldBitmap = API.SelectObject(memDc, hBitmap);
//Display-rectangle
Size size = bmp.Size;
Point pointSource = new Point(0, 0);
Point topPos = new Point(this.Left, this.Top);
//Set up blending options
API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
blend.BlendOp = API.AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = API.AC_SRC_ALPHA;
API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, API.ULW_ALPHA);
//Clean-up
bmp.Dispose();
API.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
API.SelectObject(memDc, oldBitmap);
API.DeleteObject(hBitmap);
}
API.DeleteDC(memDc);
}
catch (Exception)
{
}
}
这里有一些图片可以更好地解释
如果要在使用
UpdateLayeredWindow
API的分层窗口中使用常规控件,则需要重写控件的OnPaint
方法,将图形重定向到屏幕外位图,稍后使用UpdateLayeredWindow
方法更新窗口外观
如果您不想深入了解控件代码,或者没有太多定制控件,WM_PRINT
消息可用于强制控件将自己绘制到提供的设备上下文中。经典窗口子类化(SetWindowLong
/GetWindowLong
)用于捕捉控件自身失效的时刻,这很有用,但可能有点危险-您必须注意回调链
最后,您可以使用轻量级(无窗口)控件。它们使用表单消息队列接收事件并绘制自身,因此只需要修改表单绘制代码。一些标准winforms控件支持此模式。您需要调用
base.OnPaint(e)代码>从覆盖的OnPaint中调用。是在UpdateFormDisplay之后还是之前调用它?我尝试了这两种方法,但似乎都不适用于非托管结构。@user2920222请尝试将UpdateFormDisplay
放在OnPaintBackground
中?顺便说一句,您不应该尝试过多地定制winforms
,如果您想要更好的解决方案,请尝试使用WPF
。