使用WTL实现不规则窗口

不规则窗口又叫“异形”窗口,现在游戏的启动器界面都是这个,像完美的《诛仙》和《口袋西游》、金山的《剑侠》等,很有个性,非常漂亮。本文介绍如何用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扣一下边就能解决这个问题了。

转载于:https://www.cnblogs.com/skyman/archive/2008/07/28/irregular_window.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 WTL(Windows Template Library)进行 Windows 桌面应用开发是一个不错的选择。WTL 是一个轻量级的 C++ 模板库,基于 ATL(Active Template Library),它提供了一套简洁而高效的类和模板来开发 Windows 桌面应用程序。 以下是一个使用 WTL 创建一个简单窗口的示例: ```cpp #include <atlbase.h> #include <atlapp.h> #include <atlwin.h> class CMainWindow : public CFrameWnd { public: CMainWindow() { Create(NULL, _T("WTL Application")); } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd) ON_WM_PAINT() ON_WM_DESTROY() END_MESSAGE_MAP() void CMainWindow::OnPaint() { CPaintDC dc(m_hWnd); CRect rect; GetClientRect(&rect); dc.DrawText(_T("Hello, WTL!"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } void CMainWindow::OnDestroy() { PostQuitMessage(0); } int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nShowCmd) { CAppModule appModule; appModule.Init(NULL, hInstance); CMainWindow mainWindow; mainWindow.ShowWindow(nShowCmd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } appModule.Term(); return msg.wParam; } ``` 在这个示例中,我们创建了一个名为 "CMainWindow" 的类,继承自 WTL 的 CFrameWnd 类。在类中,我们通过重写 OnPaint 和 OnDestroy 方法来处理窗口的绘制和销毁事件。然后,在 _tWinMain 函数中,我们初始化 WTL 应用程序模块,并创建一个 CMainWindow 对象,最后进入消息循环以响应窗口消息。 请注意,使用 WTL 进行开发需要先安装 WTL 库,并将其包含到项目中。你可以从 WTL 官方网站(https://sourceforge.net/projects/wtl/)下载最新的 WTL 版本。 这只是 WTL 开发的简单示例,你可以根据需要进行进一步的开发和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值