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绘制的

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

(0)

相关推荐

  • C#实现类似qq的屏幕截图程序

    因为近来想写个类似于远程桌面监控的程序,该程序中要用到屏幕捕捉.为实现该程序的一部分功能,做了个小DEMO.程序很简单,用到的技术也不多,只能实现类似qq的截图功能(方法虽然很笨)程序流程如下: 1.截取整个屏幕并保存2.新开一个全屏窗口,将保存的屏幕作为背景3.鼠标拖动改变截取范围,右键取消4.双击截取,保存在粘贴板,全屏窗口关闭 好了,下面的是代码部分 首先新建一个项目ScreenCutter(VS2005),将窗体名改为MainForm,再新建一个窗体ScreenBody.添加一个按钮bt

  • C#截图程序类似腾讯QQ截图实现代码

    最近把以前制作的截图程序重新写了一下动了一个大手术 高质量仿照的TX的截图程序 先看几个效果图 拖动过程中显示当前鼠标下一小块的图像信息 尺寸.颜色信息的  注意 这里颜色是用的ARGB 本来截图的话RGB就够了 可是我把那个做成了控件 不仅截图可用 其他地方也可用作图像的选取 具体看代码就知道了 并且我还加了一个可以截图的同时把鼠标也捕获下来 现在看到的是我自己的截图程序 那个工具条啥的 是从TX的截图程序上面拔下来的 上面是几个工具条上的工具的三种粗细型号的展示 看到的蓝色的粗的刷笔 本来想

  • C#实现简单的登录界面

    首先我们来看一个简单的制作过程 打开visual 2010,新建窗体,既然是登录窗口,那么就不让它出现最大化.最小化以及拖拉大小功能(上一节已经提到过怎么设置大小),如图所示,甚至窗体的Text属性值为"登录窗口",大小随意. 创建窗体之后就开始界面详细的组件布局了,主要是在左边拖拉控件,然后放到窗体中去,定义属性值.这些都比较简单. 到了代码响应阶段,双击登录按钮,进入代码视图: private void button1_Click(object sender, EventArgs

  • C#中使用IrisSkin2.dll美化WinForm程序界面的方法

    一.添加控件IrisSkin2.dll.方法:        1.右键"工具箱"."添加选项卡",取名"皮肤".        2.右键"皮肤","选择项"弹出对话框        3.点击"浏览",找到IrisSkin2.dll,,next,next,确定.        4.在皮肤里会出现.        5.把SkinEngine拖到设计界面,会出现在下面. 二,把皮肤文件中以ss

  • C#定制Excel界面并实现与数据库交互的方法

    Excel是微软办公套装软件的一个重要的组成部分,它可以进行各种数据的处理.统计分析和辅助决策操作,广泛地应用于管理.统计财经.金融等众多领域.(另外,Excel还是伦敦一所会展中心的名称)..NET可以创建Excel Add-In对Excel进行功能扩展,这些扩展的功能包括自定义用户函数,自定义UI,与数据库进行数据交互等. 一 主要的Excel开发方式 1 VBA VBA是一种Visual Basic的宏语言,它是最早的Office提供定制化的一种解决方案,VBA是VB的一个子集,和Visu

  • c#制作类似qq安装程序一样的单文件程序安装包

    复制代码 代码如下: using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;using System.Xml;using System.IO;using System.IO.Compressi

  • C#中载入界面的常用方法

    本文实例讲述了C#中载入界面的常用方法.分享给大家供大家参考.具体方法分析如下: 方法1.采用事件委托的方法  对象:主窗体:FrmMain 加载窗体:FrmLoading  思路:  在主窗体加载前显示窗体FrmLoading,当主窗体加载完毕后(第一次显示的时候),关闭FrmLoading C#代码如下所示: 复制代码 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; usin

  • C#开发Windows服务实例之实现禁止QQ运行

    本实例主要实现下面三个基本功能 1.C#开发windows服务 2.禁止QQ等程序运行 3.为windows服务创建自动安装程序 下面针对这三个基本功能进行实现 一.C#开发windows服务 Windows服务在VS以前的版本中叫NT服务,在VS.NET启用了新的名称.用C#创建windows服务不是一件困难的事,下页针对服务创建.启动.停止做详细介绍 1.首先在vs中添加一winform程序KillService 2.在解决方案添加新项中添加Windows服务 3.打开服务页面,切换至代码页

  • C#编程实现QQ界面的方法

    本文实例讲述了C#编程实现QQ界面的方法.分享给大家供大家参考,具体如下: 步骤: 1.新建一个页面,假如说叫VerticalMenu 2.把html代码copy到html代码区 3.把LoadTopMenu方法copy到cs代码区 4.运行即可 1.html代码 <STYLE type="text/css"> A:link {}{ COLOR: #000000; FONT-SIZE: 12px; TEXT-DECORATION: none} A:visited {}{ C

  • c#调用qq邮箱smtp发送邮件修改版代码分享

    复制代码 代码如下: try            {                MailMessage mm = new MailMessage();                MailAddress Fromma = new MailAddress("xxxx@qq.com");                MailAddress Toma = new MailAddress("MMMMMMM@qq.com", null);              

  • c#调用存储过程实现登录界面详解

    1,创建存储过程 复制代码 代码如下: create proc Pro_Login(@UserName nvarchar(10),@PassWord nvarchar(10))as select * from [User] UserName=@UserName and PassWord=@PassWord 2,通过类是实现配置数据库字符串连接 复制代码 代码如下: class ConnectionString{public static string conStr = "Data Source=

  • C#读取QQ纯真IP数据库QQWry.Dat的代码

    纯真版QQ IP数据库 复制代码 代码如下: using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Web; using System.Configuration; namespace BLL { public class IPLocationSearch { private static readonly QQWry qq = new QQWry(Conf

  • C#多线程与跨线程访问界面控件的方法

    本文实例讲述了C#多线程与跨线程访问界面控件的方法.分享给大家供大家参考.具体分析如下: 在编写WinForm访问WebService时,常会遇到因为网络延迟造成界面卡死的现象.启用新线程去访问WebService是一个可行的方法. 典型的,有下面的启动新线程示例: 复制代码 代码如下: private void LoadRemoteAppVersion()  {      if (FileName.Text.Trim() == "") return;      StatusLabel

随机推荐