使用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)

 
 
 
         
» 轉載請注明來源及鏈接: 未來代碼研究所


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM