此代码是对此处代码的翻译(有少量解释):
Windows Form Transparent Background Image.
最初来自 Microsoft 示例代码库(至少在他们杀死它之前是这样)。
当窗体呈现透明时,将其 TransparencyKey 设置为与 BackGroundColor 使用的相同颜色,然后在透明上绘制半透明位图在窗体的表面,位图的抗锯齿部分不会与窗体后面的任何东西混合。
用作TransparencyKey 的颜色可能会影响渲染结果,但半透明像素(尤其是位图边缘附近的像素)将始终在不同背景上可见,因为没有混合 .
为了解决这个问题,我们可以建一个Layered Window:
系统自动组合重绘分层窗口,
底层应用程序的窗口。因此,分层窗口是
渲染流畅,没有复杂窗口典型的闪烁
地区。此外,分层窗口可以是部分半透明的,
也就是说,alpha 混合。
要创建分层表单,我们可以设置 WS_EX_LAYERED 扩展样式覆盖表单的 CreateParams 属性:
Protected Overrides ReadOnly Property CreateParams As CreateParams
Get
Dim parms As CreateParams = MyBase.CreateParams
parms.ExStyle = parms.ExStyle Or WS_EX_LAYERED
Return parms
End Get
End Property
Windows 8+:顶级窗口和子窗口支持WS_EX_LAYERED 样式。以前的 Windows 版本仅对顶级窗口支持此样式。
要绘制一个可以与背景混合的位图,我们在窗口设备上下文中选择一个位图,然后调用UpdateLayeredWindow,使用BLENDFUNCTION 结构指定渲染类型。
此结构允许定义 (BlendOp) 如何混合源位图和目标位图(实际上,唯一可能的操作是 Source Over,AC_SRC_OVER),级别应用于源位图的不透明度(SourceConstantAlpha:255 = 不透明,0 = 完全透明)以及如何解释源位图和目标位图的颜色(@987654340 @)。
在这里,我们想要混合具有 Alpha 通道(每像素 Alpha)的源位图,因此它是半透明的:我们将 AC_SRC_ALPHA 指定为 AlphaFormat(参见关于如何根据源 bItmap 的颜色类型解释颜色混合的文档)。
就是这样。
要构建分层表单,请将新表单添加到项目中,更改构造函数,如下所示,添加 CreateParams 覆盖,WndProc 覆盖(如果表单可以拖动它)和 @ 987654345@ 方法调用,激活源 Bitmap(在构造函数中传递)和 Form 的 DC 的 alpha 混合。
另外,将NativeMethods 支持类添加到项目中:
► 可以像往常一样创建表单,在这种情况下,将 Bitmap 对象传递给它的构造函数:
(位图格式必须是 32 位 ARGB - 带有 alpha 通道的 PNG 即可)
Dim layeredForm As New PerPixelAlphaLayeredForm(bitmap)
layeredForm.Show()
Public Class PerPixelAlphaLayeredForm
Public Sub New()
Me.New(Nothing)
End Sub
Public Sub New(bitmap As Bitmap)
InitializeComponent()
Me.LayerBitmap = bitmap
End Sub
Private ReadOnly Property LayerBitmap As Bitmap
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
If Me.LayerBitmap IsNot Nothing Then
Me.ClientSize = Me.LayerBitmap.Size
Dim screenSize = Screen.FromHandle(Me.Handle).Bounds.Size
Me.Location = New Point((screenSize.Width - Me.Width) \ 2, (screenSize.Height - Me.Height) \ 2)
SelectBitmap(Me.LayerBitmap)
' Or, call the SelectBitmapFadeOut() method
' Task.Run(Function() SelectBitmapFadeOut(Me.LayerBitmap))
End If
Me.TopMost = True
End Sub
Private Sub SelectBitmap(bitmap As Bitmap)
NativeMethods.SelectBitmapToLayeredWindow(Me, bitmap, 255)
End Sub
Private Async Function SelectBitmapFadeOut(bitmap As Bitmap) As Task
Dim fadeProgress As Integer = 255
For i = fadeProgress To 1 Step -1
BeginInvoke(New MethodInvoker(Sub() NativeMethods.SelectBitmapToLayeredWindow(Me, bitmap, fadeProgress)))
fadeProgress -= 1
Await Task.Delay(10)
Next
End Function
Protected Overrides ReadOnly Property CreateParams As CreateParams
Get
Dim parms As CreateParams = MyBase.CreateParams
If Not DesignMode Then parms.ExStyle = parms.ExStyle Or NativeMethods.WS_EX_LAYERED
Return parms
End Get
End Property
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = NativeMethods.WM_NCHITTEST Then
m.Result = New IntPtr(NativeMethods.HTCAPTION)
Else
MyBase.WndProc(m)
End If
End Sub
End Class
NativeMethods 支持类:
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Friend Class NativeMethods
Public Const HTCAPTION As Integer = &H2
Public Const WM_PAINT = &HF
Public Const WM_NCHITTEST As Integer = &H84
Public Const WS_EX_LAYERED As Integer = &H80000
Public Const AC_SRC_OVER As Byte = 0
Public Const AC_SRC_ALPHA As Byte = 1
<Flags>
Friend Enum ULWFlags
ULW_COLORKEY = &H1
ULW_ALPHA = &H2
ULW_OPAQUE = &H4
ULW_EX_NORESIZE = &H8
End Enum
<StructLayout(LayoutKind.Sequential)>
Friend Structure POINT
Public x As Integer
Public y As Integer
Public Sub New(X As Integer, Y As Integer)
Me.x = X
Me.y = Y
End Sub
End Structure
<StructLayout(LayoutKind.Sequential)>
Friend Structure SIZE
Public cx As Integer
Public cy As Integer
Public Sub New(cX As Integer, cY As Integer)
Me.cx = cX
Me.cy = cY
End Sub
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)>
Friend Structure ARGB
Public Blue As Byte
Public Green As Byte
Public Red As Byte
Public Alpha As Byte
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)>
Friend Structure BLENDFUNCTION
Public BlendOp As Byte
Public BlendFlags As Byte
Public SourceConstantAlpha As Byte
Public AlphaFormat As Byte
End Structure
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function UpdateLayeredWindow(hWnd As IntPtr, hdcDst As IntPtr, ByRef pptDst As POINT,
ByRef psize As SIZE, hdcSrc As IntPtr, ByRef pprSrc As POINT, crKey As Integer,
ByRef pblend As BLENDFUNCTION, dwFlags As ULWFlags) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function SetLayeredWindowAttributes(hWnd As IntPtr, crKey As Integer,
bAlpha As Byte, dwFlags As ULWFlags) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function ReleaseDC(hWnd As IntPtr, hDC As IntPtr) As Integer
End Function
<DllImport("gdi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function CreateCompatibleDC(hDC As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function GetDC(hWnd As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function DeleteDC(hdc As IntPtr) As Boolean
End Function
<DllImport("gdi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function SelectObject(hDC As IntPtr, hObject As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function DeleteObject(hObject As IntPtr) As Boolean
End Function
Public Shared Sub SelectBitmapToLayeredWindow(form As Form, bitmap As Bitmap, opacity As Integer)
If bitmap.PixelFormat <> PixelFormat.Format32bppArgb Then
Throw New ApplicationException("The bitmap must be 32bpp with alpha-channel.")
End If
Dim screenDc As IntPtr = GetDC(IntPtr.Zero)
Dim sourceDc As IntPtr = CreateCompatibleDC(screenDc)
Dim hBitmap As IntPtr = IntPtr.Zero
Dim hOldBitmap As IntPtr = IntPtr.Zero
Try
' Get handle to the New bitmap and select it into the current device context.
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0))
hOldBitmap = SelectObject(sourceDc, hBitmap)
Dim windowLocation As New POINT(form.Left, form.Top)
Dim windowSize As New SIZE(bitmap.Width, bitmap.Height)
Dim sourceLocation As New POINT(0, 0)
Dim blend As New BLENDFUNCTION() With {
.BlendOp = AC_SRC_OVER,
.BlendFlags = 0,
.SourceConstantAlpha = CType(opacity, Byte),
.AlphaFormat = AC_SRC_ALPHA
}
' Update the window.
' Handle => Handle to the layered window
' screenDc => Handle to the screen DC
' windowLocation => Screen position of the layered window
' windowSize => SIZE of the layered window
' sourceDc => Handle to the layered window surface DC
' sourceLocation => Location of the layer in the DC
' 0 => Color key of the layered window
' blend => Transparency of the layered window
' ULW_ALPHA => Use blend as the blend function
UpdateLayeredWindow(form.Handle, screenDc, windowLocation, windowSize,
sourceDc, sourceLocation, 0, blend, ULWFlags.ULW_ALPHA)
Finally
' Release device context.
ReleaseDC(IntPtr.Zero, screenDc)
If hBitmap <> IntPtr.Zero Then
SelectObject(sourceDc, hOldBitmap)
DeleteObject(hBitmap)
End If
DeleteDC(sourceDc)
End Try
End Sub
End Class
您可以从 Google 云端硬盘下载 Sample Project。
使用 .Net Framework 4.7.2 构建 - 任何其他框架 4.5.2+ 都可以