240 likes | 427 Views
建立 不規則形狀 的視窗. 井民全製作. SetWindowRgn API. 利用 SetWindowRgn 我們可以指定視窗的輪廓. // 建立橢圓形狀的視窗範例 HRGN rgn; rgn = CreateEllipticRgn(0,0,200,100); // 建立橢圓 region SetWindowRgn (rgn,TRUE); // 設定目前視窗的外型. 當呼叫後 , 是否要重畫視窗. 指定輪廓. 橢圓視窗 – 以 Dialog 為例.
E N D
建立不規則形狀的視窗 井民全製作
SetWindowRgn API • 利用 SetWindowRgn我們可以指定視窗的輪廓 // 建立橢圓形狀的視窗範例 HRGN rgn; rgn = CreateEllipticRgn(0,0,200,100); // 建立橢圓 region SetWindowRgn(rgn,TRUE); // 設定目前視窗的外型 當呼叫後,是否要重畫視窗 指定輪廓
橢圓視窗 –以 Dialog 為例 BOOL CTriangleDemo2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // 建立橢圓形狀的視窗 HRGN rgn; rgn = CreateEllipticRgn(0,0,200,100); // 建立橢圓 region SetWindowRgn(rgn,TRUE); // 設定目前視窗的外型 return TRUE; } 在 InitDialog 中加入 void CTriangleDemo2Dlg::OnPaint() { //重新畫元件 CDialog::OnPaint(); }
不規則形狀視窗通常都不會有 Title 所以,當你要移動視窗時,就必須要有特殊的處理 • 請你練習一下
加入滑鼠 Drag的功能 • Mouse Event Handle 自動產生對應的function 骨架 1. 選擇 Messages 2 void CTriangleDemo2Dlg::OnLButtonDown(UINT nFlags, CPoint point) { // 處理滑鼠左鍵按下的程式 }
自行加入滑鼠事件-- OnLButtonDown // [滑鼠功能] 當滑鼠左鍵按下時 void CTriangleDemo2Dlg::OnLButtonDown(UINT nFlags, CPoint point) { if ( !(m_dwFlags & DRAGGING) ) { // 若目前不是 dragging 狀態 m_pntMouse = point; m_dwFlags |= DRAGGING; // 設定目前為 Drag SetCapture();// 設定接收滑鼠輸入 } CDialog::OnLButtonDown(nFlags, point); }
自行加入滑鼠事件-- OnLButtonUp //[滑鼠功能] 當滑鼠左鍵彈起時 void CTriangleDemo2Dlg::OnLButtonUp(UINT nFlags, CPoint point) { if ( m_dwFlags & DRAGGING ) { // 若目前是 dragging 狀態 m_dwFlags &= ~DRAGGING; ReleaseCapture();// release 滑鼠輸入 } CDialog::OnLButtonUp(nFlags, point); }
自行加入滑鼠事件-- OnMouseMove // [滑鼠功能] 當滑鼠移動時, 移動視窗的位置 void CTriangleDemo2Dlg::OnMouseMove(UINT nFlags, CPoint point) { if ( m_dwFlags & DRAGGING ) { // 若目前是 Dragging 狀態,且滑鼠正在移動 RECT rect; GetWindowRect( &rect ); // 取出視窗位置 // 設定視窗的新位置 rect.left += point.x - m_pntMouse.x; rect.top += point.y - m_pntMouse.y; SetWindowPos( NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE ); } CDialog::OnMouseMove(nFlags, point); } 計算偏移量 指定視窗位置與寬高 設定目前視窗的 z-order (目前 ignore)
練習 HRGN rgn; INT num[1]; POINT points[10]; num[0]=10; points[0].x = 304; points[0].y = 24; points[1].x = 232; points[1].y = 160; points[2].x = 64; points[2].y = 160; points[3].x = 192; points[3].y = 264; points[4].x = 136; points[4].y = 392; points[5].x = 304; points[5].y = 336; points[6].x = 456; points[6].y = 392; points[7].x = 424; points[7].y = 264; points[8].x = 552; points[8].y = 160; points[9].x = 384; points[9].y = 160; rgn = CreatePolyPolygonRgn( points, num, 1, WINDING ); SetWindowRgn(rgn, true); • 請建立星星形狀的視窗 參考程式碼
以BITMAP圖案為輪廓 • 重點是讀取影像mask, 產生 Region 描述 紅色為背景 Mask 影像 建構出來的視窗形狀
指定目前的 instance 圖檔 使用實際的寬高 指定圖檔型態 以BITMAP圖案為輪廓 // ==================== 建立形狀 ===================== // Step 1: 載入影像 HBITMAP hBmp = (HBITMAP) LoadImage( AfxGetInstanceHandle(), "Rgn.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); if ( hBmp == NULL ) return TRUE; // Step 2:建立一個 Region, 令紅色為透明色 (transparent) HRGN hRgn = CreateRgnFromFile( hBmp, RGB(255,0,0) ); // Step 3:設定視窗大小與影像大小相同 SetWindowPos( NULL, 0, 0, m_dwWidth, m_dwHeight, SWP_NOZORDER | SWP_NOMOVE ); // Step 4:設定視窗的形狀 SetWindowRgn( hRgn, TRUE ); // ==================== End =====================
CreateRgnFromFile • 這個部分需要大量的BMP 檔的相關知識 • 請直接參考 SOURCE CODE
視窗繪圖原理概念Device Context • 當你想要在 window client area 畫圖或印出資料 你要透過 DC (Device Context) 即將輸出的資料 泛指任意輸出裝置 (螢幕,印表機)或檔案 DC 應用程式 GDI (圖形裝置介面 API) DC
MFC的 CDC 類別 內容 m_hDC: 對應到目前的輸出 Device m_AttributeDC:讀取 DC 屬性用 CDC 衍生四種子類別 CDC CClientDC CWindowDC CPaintDC CMetaFileDC 回應 WM_Paint Message (即 OnDraw 傳進來 的參數) 對應到視窗 Client area 對應到整個 視窗(Frame 與 control) 對應到特殊檔案 (向量格式檔案)
SelectObject function • 我們可以為裝置指定物件 • Brush 填滿的形式 • Pen 外框部分(視窗) • Bitmap • Font • Rgn • Palette (調色盤)
建立一個對應於目前工作區域的DC // Step 4: 加上背景 CDC* dc = GetDC(); // 取得目前 client area 的 DC m_dcBkGrnd = CreateCompatibleDC( dc->m_hDC ); // 建立一個memory DC ReleaseDC( dc ); // 使用完後,必須 release 該 DC // 指定一張影像到背景DC SelectObject( m_dcBkGrnd, hBmp );
// ==================== 建立形狀 ===================== // Step 1: 載入影像 HBITMAP hBmp = (HBITMAP)LoadImage( AfxGetInstanceHandle(), "Rgn.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); if ( hBmp == NULL ) return TRUE; // Step 2:建立一個 Region, 令紅色為透明色 (transparent) HRGN hRgn = CreateRgnFromFile( hBmp, RGB(255,0,0) ); // Step 3:設定視窗大小與影像大小相同 SetWindowPos( NULL, 0, 0, m_dwWidth, m_dwHeight, SWP_NOZORDER | SWP_NOMOVE ); // Step 5:設定視窗的形狀 SetWindowRgn( hRgn, TRUE ); // ==================== End ===================== 為視窗指定背景的部分 // Step 4: 加上背景 CDC* dc = GetDC(); // 取得目前 client area 的 DC m_dcBkGrnd = CreateCompatibleDC( dc->m_hDC ); // 建立一個memory DC ReleaseDC( dc ); // 使用完後,必須 release 該 DC // 指定一張影像到背景DC SelectObject( m_dcBkGrnd, hBmp );
畫上背景 void CTriangleDemo2Dlg::OnPaint() { // 取得目前視窗 client 區的 DC CPaintDC dc(this); // device context for painting // 在目前視窗上,畫上背景 if ( m_dcBkGrnd ) BitBlt( dc.m_hDC, 0, 0, m_dwWidth, m_dwHeight, m_dcBkGrnd, 0, 0, SRCCOPY ); }
Window Property 應該選擇沒有 border • 否則會造成 無法對準的情況
Appendix: BCB 的部分 #include <winuser.h>//Is user for SetWindowRgn()#include <wingdi.h>//Is user for CreatePolygonRgn() void __fastcall FormName::FormCreate(TObject *Sender){ HRGN Region; POINT Points[4]; //Define the points accross down Points[0] = Point(100 , 30 ); Points[1] = Point(200 , 200 ); Points[2] = Point(0 , 200 ); Points[3] = Point(105 , 30 ); //Define the region Region = CreatePolygonRgn(Points, 4, ALTERNATE); //Set the window to have the above defined regionSetWindowRgn(Handle, Region , True);} • 其中包含 • VB example • Delphi example 這個部分的程式碼來源:http://ftp.newave.net.au/~akia/rgn.htm#C%20Example
參考資料 • http://visualcpp.net/index.php?qID=31 • 精通視窗程式設計, 位元文化工作室 P.P.12-4
附錄: • 如果你把 #include “stdafx.h”拿掉時, 通常會出現 • “fatal error C1010: 尋找先行編譯標頭檔指示詞時找到未預期的檔案結尾“ 等錯誤訊息. • 你可以把 precompiled Header 取消