使用WTL實現不規則視窗

來源:互聯網
上載者:User

不規則視窗又叫“異形”視窗,現在遊戲的啟動器介面都是這個,像完美的《誅仙》和《口袋西遊》、金山的《劍俠》等,很有個性,非常漂亮。本文介紹如何用WTL來實現“異形視窗”。

 

1. 用Wizard建立一Dialog項目,設定視窗的“Border”屬性為None(即無標題列);

2. 載入位元影像:

BOOL CMainDlg :: LoadBitmap (UINT nIDResource) // nIDResource:位元影像的資源ID
{
  // 載入位元影像
 m_bmBitmap = new CBitmap;
 if (!m_bmBitmap->LoadBitmap (nIDResource))
  return FALSE;

 BITMAP bm;
 m_bmBitmap->GetBitmap (&bm);
 int w = bm.bmWidth;
 int h = bm.bmHeight;

 
 m_bBitmapCreated = TRUE;
 m_bBitmapExists = TRUE;

 return TRUE;
}

 

3. 設定繪製地區:

void CMainDlg::MakeWindowRgn ()
{
   // window rect - client rect
  CRect rcWnd;
  GetWindowRect (rcWnd);

  CRgn rgn;
  rgn.CreateRectRgn (rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom);

  CRect rcClient;
  GetClientRect (rcClient);
  ClientToScreen (rcClient);

  CRgn rgnClient;
  rgnClient.CreateRectRgn (rcClient.left, rcClient.top, rcClient.right,
   rcClient.bottom);

  
  rgn.CombineRgn (HRGN(rgn), HRGN(rgnClient), RGN_XOR);

  // 得到位元影像DC
  CDC dcImage;
  dcImage.CreateCompatibleDC (NULL);

  HBITMAP hOldBmp = dcImage.SelectBitmap(*m_bmBitmap);

  // 得到位元影像的寬度和高度  

  BITMAP bm;
  m_bmBitmap->GetBitmap (&bm);

  // 得到視窗的寬度和高度
  CRect rc;
  GetClientRect (rc);

  // 得到最小的寬度和高度
  int width = min (bm.bmWidth, rc.Width());
  int height = min (bm.bmHeight, rc.Height());

  // RLE(run-length)演算法:row_start 是找到的第一個不透明像素,一旦找到透明像素,則就會建立一直線地區。然後row_start 就變為下一個不透明像素
  int row_start;

  // 遍曆所有行
  for (int y=0; y<height; y++)
  {
   // 從頭開始   

   row_start = 0;

   int x;
   // 遍曆所有列
   for (x=0; x<width; x++)
   {
    // 若該像素是透明的
    if (dcImage.GetPixel(x, y) == m_colTrans) //m_colTrans:透明色(即位元影像中這個顏色的部分是透明的)
    {
     // 如果還沒找到不透明的像素,則繼續搜

     if (row_start == x) row_start ++;
     else
     {

      // 已經找到一不透明線段的開始(row_start)和結尾(x),將它加到要繪製的地區裡
      CRgn rgnAdd;
      rgnAdd.CreateRectRgn (row_start, y, x, y+1);
      rgn.CombineRgn (HRGN(rgn), HRGN(rgnAdd), RGN_OR);
      row_start = x+1;
     }
    }
   }

   // 若最後一個像素仍是不透明的,則再建立一個地區
   if (row_start != x)
   {
    CRgn rgnAdd;
    rgnAdd.CreateRectRgn (row_start, y, x, y+1);
    rgn.CombineRgn (HRGN(rgn), HRGN(rgnAdd), RGN_OR);
   }
  }

  SetWindowRgn (rgn, TRUE);
}

 

3. 處理背景擦除
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)

 

LRESULT CMainDlg::OnEraseBkgnd (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
 HDC  hDC = (HDC) wParam;

 // 得到視窗的用戶端區域 

 CRect rc;
 GetClientRect (rc);

 // 得到位元影像DC
 CDC dcImage;
 dcImage.CreateCompatibleDC (hDC);
 HBITMAP hOldBmp = dcImage.SelectBitmap(*m_bmBitmap);

 // 得到位元影像寬和高
 BITMAP bm;
 m_bmBitmap->GetBitmap (&bm);

 // 使用最小寬和高

 int width = min (bm.bmWidth, rc.Width());
 int height = min (bm.bmHeight, rc.Height());

 // 繪製位元影像為視窗背景
 BitBlt (hDC, 0, 0, rc.Width(), rc.Height(), dcImage, 0, 0, SRCCOPY);

 dcImage.SelectBitmap (hOldBmp);
 dcImage.DeleteDC ();


 return TRUE;
}

 

4. 處理左鍵按下(用於拖動視窗)
 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)

 

 LRESULT CMainDlg::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
  CPoint pt(lParam);

 // 欺騙視窗,讓它以為滑鼠點擊的是標題列
  PostMessage (WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pt.x,pt.y));

 return 0;
}

效果如所示:

 

 

 

註:由於我隨便選的一張圖片,其周圍背景不是純粹的全部黑色,所以邊緣會有毛刺,用Photoshop扣一下邊就能解決這個問題了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.