使用Win32 API创建不规则形状&带透明色的窗口

前一阵突然想起了9月份电面某公司实习时的二面题,大概就是说怎么用Win32 API实现一个透明的窗口,估计当时我的脑残答案肯定让面试官哭笑不得吧。所以本人决定好好研究下这个问题。经过一下午的摸索,基本掌握了使用Win32 API创建各种匪夷所思的窗口的基本思路。

(以下文字基于本人的个人理解,由于本人技术和经验原因不保证正确性,希望各位不吝指正)

首先我们需要了解一些基础知识。

1、Layered Windows。这是Windows2000开始引入的新概念,重新定义了窗口的Hit Testing方法,以前都是把窗口按rectangle的方式裁剪,而把窗口加上WS_EX_LAYERED的Style后就可以根据窗口的形状和像素值进行Hit Testing[1],这样我们的不规则窗口就变成了真正意义上的独立窗口,而不是传统的被一个不可见的矩形窗口所包含。

Layered Windows支持两种绘制方式,一种是采用UpdateLayeredWindow函数,优点是是一劳永逸,不需要在窗口函数中响应各种重绘事件,缺点嘛大概就是这高科技玩意让人一时半会接受不了= =另一种方式就是先用SetLayeredWindowAttributes函数设置关于窗口透明度的信息,然后用传统方式,在窗口函数中响应各种重绘事件。然而我们其实似乎并不需要关注WM_PAINT,只要在WM_CREATE中初始化一下窗口的全局背景(颜色和SetLayeredWindowAttributes所定义的相同),然后在WM_ERASEBKGND中更新一些颜色与SetLayeredWindowAttributes定义的不同的细节区域之处便可。

2、SetWindowRgn函数。这个函数用来定义窗口的区域,我们的不规则形状由此而来。这个函数和它的朋友们十分强大,不仅可以定义独立的基本形状的区域,还可以通过运算来组合已有区域从而产生新的区域。下面的实例就通过CombineRgn函数的帮助来产生了一个孔方兄形状的窗口。

好了,基本知识我们已经掌握了,下面来看看我做的示例程序的运行效果:

怎么样,还算比较cool吧。下面是完整代码:

#include <windows.h>

LRESULT _stdcall WinProc (HWND hWnd ,  UINT uMsg ,  WPARAM wParam ,  LPARAM lParam )
{
      static  HDC hDC   =  GetWindowDC (hWnd ) ;
      static  HRGN hRgn   =  CreateRectRgn ( 120 ,   70 ,   280 ,   230 ) ;

      switch (uMsg )
      {
      case  WM_ERASEBKGND :
          {
            DefWindowProc (hWnd ,  uMsg ,  wParam ,  lParam ) ;
            FillRgn (hDC ,  hRgn ,  CreateSolidBrush (RGB ( 255 ,   165 ,   0 ) ) ) ;   // Orange
            SelectObject (hDC ,  hRgn ) ;
              return   0 ;
          }

      case  WM_CREATE :
          {
            HRGN hRgn1   =  CreateEllipticRgn ( 0 ,   0 ,   400 ,   300 ) ;
            HRGN hRgn2   =  CreateEllipticRgn ( 150 ,   100 ,   250 ,   200 ) ;
            CombineRgn (hRgn1 ,  hRgn1 ,  hRgn2 ,  RGN_XOR ) ;
            SetWindowRgn (hWnd ,  hRgn1 ,  TRUE ) ;
            DeleteObject (hRgn1 ) ;
             DeleteObject (hRgn2 ) ;           
              break ;
          }
 
      case  WM_LBUTTONDOWN :
          {
            SendMessage (hWnd ,  WM_NCLBUTTONDOWN ,  HTCAPTION ,   0 ) ;
              break ;
          }

      case  WM_DESTROY :
          {
            DeleteObject (hRgn ) ;
            ReleaseDC (hWnd ,  hDC ) ;
            PostQuitMessage ( 0 ) ;
              break ;
          }
      }
      return  DefWindowProc (hWnd ,  uMsg ,  wParam ,  lParam ) ;;
}

int  _stdcall WinMain (HINSTANCE hInstance ,  HINSTANCE ,  LPSTR ,  BOOL )
{
    WNDCLASS wc   =   { 0 } ;
    wc. lpszClassName   =  L "wndclass" ;
    wc. hbrBackground   =  CreateSolidBrush (RGB ( 255 ,   99 ,   71 ) ) ;
    wc. hIcon   =  LoadIcon (NULL ,  IDI_APPLICATION ) ;
    wc. hCursor   =  LoadCursor (NULL ,  IDC_ARROW ) ;
    wc. lpfnWndProc   =  WinProc ;
    RegisterClass ( &wc ) ;

    HWND hWnd   =  CreateWindowExW (WS_EX_LAYERED ,  L "wndclass" ,  L "Window" ,  WS_POPUP |WS_VISIBLE ,  CW_USEDEFAULT ,  CW_USEDEFAULT ,   400 ,   300 ,   0 ,   0 ,  hInstance ,   0 ) ;
      if   (hWnd   ==  NULL )
          return   1 ;

    SetLayeredWindowAttributes (hWnd ,  NULL ,   178 ,  LWA_ALPHA ) ;   // Tomato

    MSG msg   =   { 0 } ;
      while   (GetMessage ( &msg ,   0 ,   0 ,   0 ) )
      {
        DispatchMessage ( &msg ) ;
      }

      return   0 ;
}

参考资料:
[1] MSDN:Layered Windows
[2] WindowsAPI_001:创建一个不规则的窗口的方法(用到Region系列API)

 
 
» 转载请注明来源及链接: 未来代码研究所
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值