使用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)
» 轉載請注明來源及鏈接:未來代碼研究所» 本文鏈接地址:http://blog.atelier39.org/winuser/188.htmlRFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成