Windows介面程式設計第四篇 異形窗體 高富帥版
上一篇《》介紹了異形視窗(異形窗體)的建立,其主要步驟為——先通過建立點陣圖畫刷來做視窗的背景畫刷,再通過SetWindowLong為窗體加上WS_EX_LAYERED屬性,然後使用SetLayeredWindowAttributes指定視窗的透明色來完成視窗形狀的調整。並且為了使異形視窗支援滑鼠的拖曳,在WM_LBUTTONDOWN訊息中作了特殊處理。
然後在下圖中有非常相似的兩個異形窗體,只不過,左邊的異形窗體小,右邊的異形窗體大。這個可以怎麼實現了?
先通過其它軟體來縮放點陣圖,然後再讓程式載入這種方式來指定異形視窗的大小。這種方法雖然可以完成任務,但畢竟太OUT了。
由《Windows
由於異形視窗執行後無法通過滑鼠來動態調整視窗大小,因此可以視窗初始化時就可以先縮放點陣圖並載入到一個緩衝HDC中,然後再在視窗背景繪製時使用BitBlt來貼圖。這種做法只需要縮放點陣圖一次,在每次背景繪製時只須拷貝點陣圖,對程式的效率會有提高。下面給出完整原始碼(下載地址:http://download.csdn.net/download/morewindows/4966819)
// 異形視窗2 在WM_ERASEBKGND訊息中自貼圖 //By MoreWindows-(http://blog.csdn.net/MoreWindows)#include <windows.h>const char szAppName[] = "異形視窗2 MoreWindows-(http://blog.csdn.net/MoreWindows)";/* * 函式名稱: GetWindowSize * 函式功能: 得到視窗的寬高 * hwnd 視窗控制代碼 * pnWidth 視窗寬 * pnHeight 視窗高*/void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);/* * 函式名稱: InitBitmapWindow * 函式功能: 點陣圖視窗初始化 * hinstance 程序例項 * nWidth 視窗寬 * nHeight 視窗高 * nCmdshow 顯示方式-與ShowWindow函式的第二個引數相同*/ BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow);// 點陣圖視窗訊息處理函式LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm); HBITMAP g_hBitmap;int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ //先建立一個無背影畫刷視窗, //然後在WM_CREATE中並指定透明顏色, 縮放點陣圖後加載至s_hdcMem中. //最後在WM_ERASEBKGND中用s_hdcMem貼圖即可 g_hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if (g_hBitmap == NULL) { MessageBox(NULL, "點陣圖載入失敗", "Error", MB_ICONERROR); return 0; } // 設定異形視窗大小 BITMAP bm; GetObject(g_hBitmap, sizeof(bm), &bm); int nWindowWidth = bm.bmWidth; int nWindowHeight = bm.bmHeight + 100; //拉高100高度 if (!InitBitmapWindow(hInstance, nWindowWidth, nWindowHeight, nCmdShow)) return 0; MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DeleteObject(g_hBitmap); return msg.wParam;}BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow){ HWND hwnd; WNDCLASS wndclass; wndclass.style = CS_VREDRAW | CS_HREDRAW; wndclass.lpfnWndProc = BitmapWindowWndPrco; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hinstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//視窗背影畫刷為空 wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR); return FALSE; } hwnd = CreateWindowEx(WS_EX_TOPMOST, szAppName, szAppName, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, nWidth, nHeight, NULL, NULL, hinstance, NULL); if (hwnd == NULL) return FALSE; ShowWindow(hwnd, nCmdshow); UpdateWindow(hwnd); return TRUE;}LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm){ static HDC s_hdcMem; //放置縮放後的點陣圖 switch (message) { case WM_CREATE: { // 設定分層屬性 SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); // 設定透明色 COLORREF clTransparent = RGB(0, 0, 0); SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY); // 縮放點陣圖 // 載入點陣圖到hdcTemp中 HDC hdc = GetDC(hwnd); HDC hdcTemp = CreateCompatibleDC(hdc); SelectObject(hdcTemp, g_hBitmap); // 得到視窗大小 int nWidth, nHeight; GetWindowSize(hwnd, &nWidth, &nHeight); // 建立與視窗大小相等且能容納點陣圖的HDC - s_hdcMem s_hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmp = CreateCompatibleBitmap(hdc, nWidth, nHeight); SelectObject(s_hdcMem, hbmp); // 將原點陣圖縮放到視窗大小 BITMAP bm; GetObject(g_hBitmap, sizeof(bm), &bm); StretchBlt(s_hdcMem, 0, 0, nWidth, nHeight, hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); // 釋放資源 DeleteDC(hdcTemp); ReleaseDC(hwnd, hdc); } return 0; case WM_KEYDOWN: switch (wParam) { case VK_ESCAPE: //按下Esc鍵時退出 SendMessage(hwnd, WM_DESTROY, 0, 0); return TRUE; } break; case WM_LBUTTONDOWN: //當滑鼠左鍵點選時可以拖曳視窗 PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0); return TRUE; case WM_ERASEBKGND: //在視窗背景中直接貼圖 { HDC hdc = (HDC)wParam; int nWidth, nHeight; GetWindowSize(hwnd, &nWidth, &nHeight); BitBlt(hdc, 0, 0, nWidth, nHeight, s_hdcMem, 0, 0, SRCCOPY); return TRUE; } case WM_DESTROY: DeleteDC(s_hdcMem); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParm);}void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight){ RECT rc; GetWindowRect(hwnd, &rc); *pnWidth = rc.right - rc.left; *pnHeight = rc.bottom - rc.top;}
執行程式將得到如文章中每一張圖右邊所示的異形視窗。
最後總結一下異形視窗的“三要素”:
1.WS_EX_LAYERED屬性
2.以點陣圖為視窗背景(自貼圖或點陣圖畫刷)
3.指定透明色
當視窗的背景用彩色圖片來裝飾時,其它控制元件如果還是用灰色的背景會顯的比較不諧調,《Windows介面程式設計第五篇 靜態控制元件背景透明化》將介紹如何為靜態框設定透明背景。