您的位置:首页 > 编程语言 > VB

[原创][VB.NET] 用LayeredWindow制作PNG透明窗体心得

2008-07-10 15:05 453 查看
[原创][VB.NET] 关于用GDI32.dll采用UpdateLayeredWindow制作PNG透明窗体的心得(HAVENT81/夜雨流星℡ From Www.Ai169.Com)

------------------------------------------------------------------------

前几天突然想制作一个窗体基类,所以去网上看了一下,发现了PNG透明窗体的源代码,代码的核心就是采用UpdateLayeredWindow的方法绘制窗体,测试了一下,界面非常爽,窗体的半透明效果感觉跟VistaGlass效果几乎一样。

但是随之而来的是遇到了一个非常棘手的问题,这个方法存在一个超级大BUG,就是无法可视化所有的控件,无论放什么控件,都无法显示(但是控件确实存在,只是没有绘制而已,我用TEXTBOX测试能够获取内容文本,也有区域感知,就是屏幕上看没有任何东西)。

基于这原因,本人上网找了资料,发现很多人也出现同样问题,后来研究一下System.Drawing.Graphics的功能,总算有了一点思路。

由于原来的设计就是利用单幅图片进行窗体绘制,所以在这个思路上,即最终用已经实现的SetBitmap()方法来实现窗体绘制,但是在图片输出之前用Graphics类进行图片叠加处理,来实现窗体内控件内容的叠加操作(也许这就是窗体绘制的最原始的方法,只是微软已经将绘制封装到了控件中而已),下面是简单的在原来窗体图片上加绘了一些字符串和一张图片的方法:

Dim _Image As Bitmap = My.Resources.Vista '最终要呈现的图片
Dim _Graphics As Graphics = Graphics.FromImage(_Image) '建立一个图片绘制对象
Dim _Brush As New SolidBrush(Color.Black) '用来处理文字的画笔

Dim _Format As New StringFormat '文本布局信息封装对象
_Format.Alignment = StringAlignment.Center '垂直文本对齐方式
_Format.LineAlignment = StringAlignment.Center '水平文本对齐方式

_Graphics.TextRenderingHint = TextRenderingHint.AntiAlias '设置高质量模式

'在原始图层上绘制字符串
_Graphics.DrawString("HAVENT81/夜雨流星℡", New System.Drawing.Font(SystemFonts.CaptionFont.FontFamily, 120.0F, FontStyle.Bold), _Brush, CSng(((Me.Width / 2))), CSng((Me.Height / 2)), _Format)

'继续在图层之上绘制一张图片,图片来源为资源文件中的 VistaItem
_Graphics.DrawImage(My.Resources.VistaItem, 10.0F, 20.0F)
_Graphics.Dispose()

Me.SetBitmap(_Image, &HFF) '利用前人总结的技术进行图片填充
_Image.Dispose()
_Format.Dispose()

下面提供的是前人提供的SetBitmap的方法(这个方法要依托一个Win32的类,类代码在后面给出):

Public Sub SetBitmap(ByVal bitmap As Bitmap, ByVal opacity As Byte)
If (bitmap.PixelFormat <> PixelFormat.Format32bppArgb) Then
Throw New ApplicationException("The bitmap must be 32ppp with alpha-channel.")
End If
Dim dC As IntPtr = Win32.GetDC(IntPtr.Zero)
Dim hDC As IntPtr = Win32.CreateCompatibleDC(dC)
Dim zero As IntPtr = IntPtr.Zero
Dim hObject As IntPtr = IntPtr.Zero
Try
zero = bitmap.GetHbitmap(Color.FromArgb(0))
hObject = Win32.SelectObject(hDC, zero)
Dim psize As New Win32.Size(bitmap.Width, bitmap.Height)
Dim pprSrc As New Win32.Point(0, 0)
Dim pptDst As New Win32.Point(MyBase.Left, MyBase.Top)
Dim pblend As New Win32.BLENDFUNCTION
pblend.BlendOp = 0
pblend.BlendFlags = 0
pblend.SourceConstantAlpha = opacity
pblend.AlphaFormat = 1
Win32.UpdateLayeredWindow(MyBase.Handle, dC, (pptDst), (psize), hDC, (pprSrc), 0, (pblend), 2)
Finally
Win32.ReleaseDC(IntPtr.Zero, dC)
If (zero <> IntPtr.Zero) Then
Win32.SelectObject(hDC, hObject)
Win32.DeleteObject(zero)
End If
Win32.DeleteDC(hDC)
End Try
End Sub

接下来就是用于API交互的WIN32类:

Friend Class Win32
' Methods
<DllImport("gdi32.dll", SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function CreateCompatibleDC(ByVal hDC As IntPtr) As IntPtr
End Function

<DllImport("gdi32.dll", SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function DeleteDC(ByVal hdc As IntPtr) As Bool
End Function

<DllImport("gdi32.dll", SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Bool
End Function

<DllImport("user32.dll", SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
End Function

<DllImport("user32.dll", ExactSpelling:=True)> _
Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer
End Function

<DllImport("gdi32.dll", ExactSpelling:=True)> _
Public Shared Function SelectObject(ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr
End Function

<DllImport("user32.dll", SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function UpdateLayeredWindow(ByVal hwnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As Point, ByRef psize As Size, ByVal hdcSrc As IntPtr, ByRef pprSrc As Point, ByVal crKey As Integer, ByRef pblend As BLENDFUNCTION, ByVal dwFlags As Integer) As Bool
End Function

' Fields
Public Const AC_SRC_ALPHA As Byte = 1
Public Const AC_SRC_OVER As Byte = 0
Public Const ULW_ALPHA As Integer = 2
Public Const ULW_COLORKEY As Integer = 1
Public Const ULW_OPAQUE As Integer = 4

' Nested Types
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Private 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)> _
Public Structure BLENDFUNCTION
Public BlendOp As Byte
Public BlendFlags As Byte
Public SourceConstantAlpha As Byte
Public AlphaFormat As Byte
End Structure

Public Enum Bool
' Fields
[False] = 0
[True] = 1
End Enum

<StructLayout(LayoutKind.Sequential)> _
Public Structure Point
Public x As Integer
Public y As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
Me.x = x
Me.y = y
End Sub
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure Size
Public cx As Integer
Public cy As Integer
Public Sub New(ByVal cx As Integer, ByVal cy As Integer)
Me.cx = cx
Me.cy = cy
End Sub
End Structure
End Class

以上只是提供了一个思路,有功夫的朋友可以修改这个方法,然后修改一些WINDOWS窗体控件,将它们转化成图像,统一用SetBitmap方法来进行输出,这样就等于完全自己处理控件的显示效果了,不过貌似工程量太庞大了点……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: