欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#中如何使用Winform实现炫酷的透明动画界面

程序员文章站 2023-11-12 15:54:10
做过.net winform窗体美化的人应该都很熟悉updatelayeredwindow吧,updatelayeredwindow可以实现窗体的任意透明,效果很好,不会有...

做过.net winform窗体美化的人应该都很熟悉updatelayeredwindow吧,updatelayeredwindow可以实现窗体的任意透明,效果很好,不会有毛边。不过使用这个api之后,会有一个问题就是无法使用普通控件,而且没有paint消息。为了解决这个问题,有两种方法。

C#中如何使用Winform实现炫酷的透明动画界面

一、使用双层窗体,底层窗体使用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重绘方式高很多,并且不卡不闪烁,支持任意透明。

下面是自己开发出来的效果:

C#中如何使用Winform实现炫酷的透明动画界面

C#中如何使用Winform实现炫酷的透明动画界面

这个是用opengl绘制的

C#中如何使用Winform实现炫酷的透明动画界面

效果是不是很酷呀,通过以上内容的介绍,希望对大家的学习有所帮助。