C#中如何使用Winform实现炫酷的透明动画界面
做过.net winform窗体美化的人应该都很熟悉updatelayeredwindow吧,updatelayeredwindow可以实现窗体的任意透明,效果很好,不会有毛边。不过使用这个api之后,会有一个问题就是无法使用普通控件,而且没有paint消息。为了解决这个问题,有两种方法。
一、使用双层窗体,底层窗体使用updatelayeredwindow作为背景,上层窗体用普通窗体,并且可以使用transparencykey或者region来实现去除不需要的窗体内容,让上层窗体能看到底层的窗体。
二、直接单层窗体,使用控件的drawtobitmap把控件图像绘制到updatelayeredwindow 的窗体上,这样就可以看到普通控件了。不过这个也有问题:1.控件内容不能自动更新 2.效率低,很多控件使用drawtobitmap绘制出的图像不完整,甚至绘制不出图像。比如textbox无法显示光标,webbrowser无法 显示内容。
三、采用directui技术,重写所有基础控件。效果最好,不过工作量巨大。
使用updatelayeredwindow时,一般是需要对bitmap缓存起来,通过设置剪辑区域,局部重绘来提高效率。另外还可以异步重绘,模拟winform的失效到重绘。
有些人会说为什么不直接用wpf啊,wpf和winform各有优缺点,适应不同的场合。winform相对于使用更简单一些,系统要求更低。当然需要看人的习惯了和擅长的。
updatelayeredwindow 基本使用方法:
protected override createparams createparams { get { createparams cp = base .createparams; cp.exstyle |= 0x00080000 ; // ws_ex_layered 扩展样式 return cp; } }
重写窗体的 createparams 属性
api调用:
public void setbitmap(bitmap bitmap, byte opacity) { if (bitmap.pixelformat != pixelformat.format32bppargb) throw new applicationexception( "位图必须是32位包含alpha 通道" ); intptr screendc = win32.getdc(intptr.zero); intptr memdc = win32.createcompatibledc(screendc); intptr hbitmap = intptr.zero; intptr oldbitmap = intptr.zero; try { hbitmap = bitmap.gethbitmap(color.fromargb( 0 )); // 创建gdi位图句柄,效率较低 oldbitmap = win32.selectobject(memdc, hbitmap); win32.size size = new win32.size(bitmap.width, bitmap.height); win32.point pointsource = new win32.point( 0 , 0 ); win32.point toppos = new win32.point(left, top); win32.blendfunction blend = new win32.blendfunction(); blend.blendop = win32.ac_src_over; blend.blendflags = 0 ; blend.sourceconstantalpha = opacity; blend.alphaformat = win32.ac_src_alpha; win32.updatelayeredwindow(handle, screendc, ref toppos, ref size, memdc, ref pointsource, 0 , ref blend, win32.ulw_alpha); } finally { win32.releasedc(intptr.zero, screendc); if (hbitmap != intptr.zero) { win32.selectobject(memdc, oldbitmap); win32.deleteobject(hbitmap); } win32.deletedc(memdc); } }
api声明:
class win32 { public enum bool { false = 0 , true } ; [structlayout(layoutkind.sequential)] public struct point { public int32 x; public int32 y; public point(int32 x, int32 y) { this .x = x; this .y = y; } } [structlayout(layoutkind.sequential)] public 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 )] public struct blendfunction { public byte blendop; public byte blendflags; public byte sourceconstantalpha; public byte alphaformat; } public const int32 ulw_colorkey = 0x00000001 ; public const int32 ulw_alpha = 0x00000002 ; public const int32 ulw_opaque = 0x00000004 ; public const byte ac_src_over = 0x00 ; public const byte ac_src_alpha = 0x01 ; [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 pprsrc, int32 crkey, ref blendfunction pblend, int32 dwflags); [dllimport( " user32.dll " , exactspelling = true , setlasterror = true )] public static extern intptr getdc(intptr hwnd); [dllimport( " user32.dll " , exactspelling = true )] public static extern int releasedc(intptr hwnd, intptr hdc); [dllimport( " gdi32.dll " , exactspelling = true , setlasterror = true )] public static extern intptr createcompatibledc(intptr hdc); [dllimport( " gdi32.dll " , exactspelling = true , setlasterror = true )] public static extern bool deletedc(intptr hdc); [dllimport( " gdi32.dll " , exactspelling = true )] public static extern intptr selectobject(intptr hdc, intptr hobject); [dllimport( " gdi32.dll " , exactspelling = true , setlasterror = true )] public static extern bool deleteobject(intptr hobject); [dllimport( " user32.dll " , entrypoint = " sendmessage " )] public static extern int sendmessage( int hwnd, int wmsg, int wparam, int lparam); [dllimport( " user32.dll " , entrypoint = " releasecapture " )] public static extern int releasecapture(); public const int wm_syscommand = 0x0112 ; public const int sc_move = 0xf012 ; public const int sc_maximize = 61488 ; public const int sc_minimize = 61472 ; }
需要呈现图像的时候调用 setbitmap 方法。只要优化好,呈现效率比普通的paint重绘方式高很多,并且不卡不闪烁,支持任意透明。
下面是自己开发出来的效果:
这个是用opengl绘制的
效果是不是很酷呀,通过以上内容的介绍,希望对大家的学习有所帮助。
上一篇: 采用easyui tree编写简单角色权限代码的方法
下一篇: 在C#中新手易犯的典型缺陷