1. 程式人生 > >Windows介面程式設計第四篇 異形窗體 高富帥版

Windows介面程式設計第四篇 異形窗體 高富帥版

               

    上一篇《》介紹了異形視窗(異形窗體)的建立,其主要步驟為——先通過建立點陣圖畫刷來做視窗的背景畫刷,再通過SetWindowLong為窗體加上WS_EX_LAYERED屬性,然後使用SetLayeredWindowAttributes指定視窗的透明色來完成視窗形狀的調整。並且為了使異形視窗支援滑鼠的拖曳,在WM_LBUTTONDOWN訊息中作了特殊處理。

然後在下圖中有非常相似的兩個異形窗體,只不過,左邊的異形窗體小,右邊的異形窗體大。這個可以怎麼實現了?

 

先通過其它軟體來縮放點陣圖,然後再讓程式載入這種方式來指定異形視窗的大小。這種方法雖然可以完成任務,但畢竟太OUT了。

由《Windows

介面程式設計第一篇點陣圖背景與點陣圖畫刷》可以想到不用點陣圖畫刷,而直接在視窗背景繪製時使用StretchBlt來縮放點陣圖至視窗大小,這樣就可以達到指定視窗大小的功能。

由於異形視窗執行後無法通過滑鼠來動態調整視窗大小,因此可以視窗初始化時就可以先縮放點陣圖並載入到一個緩衝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介面程式設計第五篇 靜態控制元件背景透明化》將介紹如何為靜態框設定透明背景。