1. 程式人生 > >VC----SDK下對視窗非客戶區的操作

VC----SDK下對視窗非客戶區的操作

視窗分成兩大部分:客戶區和非客戶區。非客戶區再次細分:標題欄,如圖片中頂部深藍色;左邊框,如圖片中紅色部分;上邊框,如圖片中綠色部分;右邊框,如圖片中右側天藍色部分;底邊框,如圖片中下面棕色部分。

之所以要有這樣的區分,是因為,我在用函式SystemParametersInfo得到視窗的非客戶區引數時,標題欄高度確實是上面深藍色部分,不能達到客戶區,在標題欄和客戶區之間還有一個白色區域,我想這可能就是上邊框吧。

需要用到的幾個函式:

PatBlt:作用是在指定的矩形區域用指定的Brush畫刷來填充這個區域。

SystemParametersInfo得到系統的一些引數,比如標題欄的高度,邊框寬度等。

GetSystemMetrics:有點和上面函式相同,但是感覺沒有上面的SystemParametersInfo函式精確。

思路:在訊息WM_NCPAINT,WM_NCACTIVATE,WM_MOVE響應時得到非客戶區的DC(區別於客戶區的DC),再得到矩形區域,用函式來填充顏色。攔截系統對這幾個訊息的處理。

注意:使用的DC一定要是非客戶區的DC,用GetWindowDC來得到控制代碼,不能用GetDC,因為GetDC得到的是客戶區的DC,這個DC只能用來塗鴉客戶區。得到邊框的寬度時,比如頂部邊框,綠色部分,要在得到的基礎上+4,否則的話不能完全填充為指定的綠色,也是個疑問。

	case WM_NOTIFY:
	case WM_MOVE:
	case WM_NCACTIVATE:
	case WM_NCPAINT:
		{
			
			//得到系統標題欄的資訊:寬度、高度、矩形區域
			int tbheight,tbwidth;
			RECT wndrect,clientrect;
			GetWindowRect(hwnd,&wndrect);
			GetClientRect(hwnd,&clientrect);
			tbheight= GetSystemMetrics(SM_CYSIZE);//標題欄寬度
			//end 得到系統標題欄的資訊
			//填充標題欄
			RECT rcWindow ;
			GetWindowRect(hwnd,&rcWindow);
			HDC hDc =  GetWindowDC(hwnd);
			HBRUSH hBrush = CreateSolidBrush(RGB(25,0,255));
			HBRUSH hOldbrush =(HBRUSH) SelectObject(hDc,(HGDIOBJ)hBrush);
			PatBlt(hDc,0,0,wndrect.right-wndrect.left,tbheight,PATCOPY);
			//end 填充標題欄
			//填充邊框
			NONCLIENTMETRICS  nonmet;
			nonmet.cbSize=sizeof(NONCLIENTMETRICS);
			SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(NONCLIENTMETRICS),&nonmet,0);

			RECT borderleft,borderright,bordertop,borderbottom;
			borderleft.left = 0;
			borderleft.right = wndrect.left+7;
			borderleft.top=tbheight;
			borderleft.bottom=wndrect.bottom;
			hBrush = CreateSolidBrush(RGB(200,0,0));
			SelectObject(hDc,(HGDIOBJ)hBrush);
			PatBlt(hDc,borderleft.left,borderleft.top,nonmet.iPaddedBorderWidth+4,borderleft.bottom-borderleft.top,PATCOPY);
			SelectObject(hDc,(HGDIOBJ)hOldbrush);

			bordertop.left=0;
			bordertop.bottom=wndrect.top+nonmet.iCaptionHeight+nonmet.iPaddedBorderWidth+4;
			bordertop.right = wndrect.right;
			bordertop.top=nonmet.iCaptionHeight;
			hBrush = CreateSolidBrush(RGB(0,200,0));
			SelectObject(hDc,(HGDIOBJ)hBrush);
			PatBlt(hDc,bordertop.left,bordertop.top,bordertop.right-bordertop.left,nonmet.iPaddedBorderWidth+5,PATCOPY);
			SelectObject(hDc,(HGDIOBJ)hOldbrush);

			borderright.left=wndrect.right-wndrect.left-nonmet.iPaddedBorderWidth-4;
			borderright.top=nonmet.iCaptionHeight;
			borderright.bottom=wndrect.bottom;
			borderright.right = wndrect.right-wndrect.left;
			hBrush = CreateSolidBrush(RGB(0,100,200));
			SelectObject(hDc,(HGDIOBJ)hBrush);
			PatBlt(hDc,borderright.left,borderright.top,nonmet.iPaddedBorderWidth+4,borderright.bottom-borderright.top,PATCOPY);
			

			borderbottom.bottom = wndrect.bottom;
			borderbottom.left=nonmet.iPaddedBorderWidth+4;
			borderbottom.right = wndrect.right-wndrect.left-nonmet.iPaddedBorderWidth-4;
			borderbottom.top = wndrect.bottom-wndrect.top-nonmet.iPaddedBorderWidth-4;
			hBrush = CreateSolidBrush(RGB(100,80,80));
			SelectObject(hDc,(HGDIOBJ)hBrush);
			PatBlt(hDc,borderbottom.left,borderbottom.top,borderbottom.right-borderbottom.left,nonmet.iPaddedBorderWidth+4,PATCOPY);
			//end 填充邊框
                        SelectObject(hDc,(HGDIOBJ)hOldbrush);
   ReleaseDC(hwnd,hDc);
//DefWindowProc(hwnd,uMsg,wParam,lParam);
return 0;//攔截系統的處理
break;
}

對DC的解釋參考文章:
http://www.codeproject.com/Articles/89996/Drawing-in-Windows-101


對標題欄的理解:

在Win7下,設定主題為Basic型別的,得到一個介面如下:

 

外圈棕色部分就是邊框,和上面說的上邊框的位置不同,在對QQ視窗進行最大化也會看到紅色的部分,這個部分是標題欄的位置。

幾點注意:

1、三個系統按鈕是為標題按鈕,標題按鈕和標題欄的寬度是一樣大小的。

2、當最大化時,邊框會消失。標準大小時,恢復狀態。

調整後上邊框為上綠色,結果如下:


而三個系統按鈕就在最左邊的位置 如圖。

像Aero主題 和QQ 、迅雷等的按鈕會發生變化,是因為是對這三個按鈕處理的結果,上面的程式也有一個問題:當在單擊到三個按鈕的位置時會出現這三個按鈕。如下:

 

就這個問題。

調整後的結果,:


對標題欄的理解:

在Win7下,設定主題為Basic型別的,得到一個介面如下:

外圈棕色部分就是邊框,和上面說的上邊框的位置不同,在對QQ視窗進行最大化也會看到紅色的部分,這個部分是標題欄的位置。

而三個系統按鈕就在最左邊的位置 如圖。

像Aero主題 和QQ 、迅雷等的按鈕會發生變化,是因為是對這三個按鈕處理的結果,上面的程式也有一個問題:當在單擊到三個按鈕的位置時會出現這三個按鈕。如下:

就這個問題。

 用點陣圖來填充矩形:

目標是把三個按鈕給覆蓋:

			//處理三個按鈕
			//第一步:定位位置--在右邊框的左邊,右側貼右邊框,左側可通過SystemParametersInfo得到按鈕寬度iCaptionHeight,再*3;上下邊框在標題欄內。
			//第二步:用圖片或者顏色給蓋上,攔截NCLBUTTONDOWN訊息。在單擊位置在按鈕區域時,分別傳送3個訊息,
			RECT btnrect;
			btnrect.bottom=nonmet.iCaptionHeight+nonmet.iBorderWidth;
			btnrect.left=wndrect.right-wndrect.left-nonmet.iCaptionHeight*3-nonmet.iBorderWidth;
			btnrect.right=btnrect.left+nonmet.iCaptionHeight*3;
			btnrect.top=nonmet.iBorderWidth;

			HDC hcomdc = CreateCompatibleDC(hDc);
			HBITMAP hbmp = LoadBitmap(g_hInstance,MAKEINTRESOURCE(IDB_BITMAP4));
			HBITMAP holdbmp=(HBITMAP)SelectObject(hcomdc,(HGDIOBJ)hbmp);
			StretchBlt(hDc,btnrect.left-nonmet.iPaddedBorderWidth-14,btnrect.top+nonmet.iPaddedBorderWidth+4,nonmet.iCaptionHeight*3+12,nonmet.iCaptionHeight,hcomdc,0,0,60,20,SRCCOPY);
			

			//end處理三個按鈕

結果如圖:

攔截訊息如下:

		GetWindowRect(hwnd,&wndrect);
		POINT *lpoint=(POINT *)lParam;
		int xPos = GET_X_LPARAM(lParam); 
		int yPos = GET_Y_LPARAM(lParam);
		if(xPos>wndrect.left+btnrect.left-10&&xPos<wndrect.left+btnrect.right-10&&yPos>wndrect.top+btnrect.top+8&&yPos<wndrect.top+btnrect.bottom)
			return 0;
		break;


 把視窗進行圓角操作:

      需要在視窗大小變化後進行圓角操作。捕捉大小變化的訊息是WM_SIZE, 這是視窗變化後的訊息。程式碼如下:

    case WM_SIZE:
        {
        RECT wndRect;
        GetWindowRect(hWnd,&wndRect);
        HRGN hRgn=CreateRoundRectRgn(0,0,wndRect.right-wndRect.left,wndRect.bottom-wndRect.top,50,50);
        SetWindowRgn(hWnd,hRgn,true);
        if(hRgn)
            DeleteObject((HGDIOBJ)hRgn);
        break;
        }