自绘非客户区

下面是网上收集来的代码,实现炫彩自绘窗口非客户区,贴出来大家参考共享...

效果如下图所示:

 

关键代码如下:

在框架类中添加:

public:
 afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
 afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
 afx_msg BOOL OnEraseBkgnd(CDC* pDC);
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
public:
 CRect    m_rtIcon;    //程序图标位置
 CRect    m_rtButtMax;   //最大化按钮位置
 CRect    m_rtButtMin;   //最小化按钮位置
 CRect    m_rtButtExit;   //关闭按钮位置

 

实现:

在OnCreate消息里添加:

CRect rtWnd;
 GetWindowRect(&rtWnd);

 CRgn rgn;
 rgn.CreateRoundRectRgn(0,0,rtWnd.Width(),rtWnd.Height(),5,5);
 SetWindowRgn((HRGN)rgn,true);

 

下面是消息部分:

void CMainFrame::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 if (m_rtButtExit.PtInRect(point)) //关闭
  SendMessage(WM_CLOSE);
 else if (m_rtButtMin.PtInRect(point)) //最小化
  SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(point.x, point.y));
 else if (m_rtButtMax.PtInRect(point))
 {
  if (IsZoomed()) //最大化
  {
   SendMessage(WM_SYSCOMMAND, SC_RESTORE, MAKELPARAM(point.x, point.y));
   CRect rtWnd;
   GetWindowRect(&rtWnd);
   CRgn rgn;
   rgn.CreateRoundRectRgn(0,0,rtWnd.Width(),rtWnd.Height(),5,5);
   SetWindowRgn((HRGN)rgn,true);
   Invalidate();
  }
  else
  {
   SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y));

   CRect rtWnd;
   GetWindowRect(&rtWnd);
   CRgn rgn;
   rgn.CreateRoundRectRgn(0,0,rtWnd.Width(),rtWnd.Height(),5,5);
   SetWindowRgn((HRGN)rgn,true);
   Invalidate();
  }
 }
 else if (!IsZoomed())
  Default();
 //CFrameWndEx::OnNcLButtonDown(nHitTest, point);
}


void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 CWindowDC dc(this);
 CWindowDC* pDC = &dc;
 CDC* pDisplayMemDC=new CDC;
 pDisplayMemDC->CreateCompatibleDC(pDC);
 CBitmap* pBitmap = new CBitmap;
 CBitmap* pOldBitmap;
 CRect rtWnd, rtButton;

 if (pDC)
 {
  GetWindowRect(&rtWnd);

  //关闭button
  if (m_rtButtExit.PtInRect(point))
   pBitmap->LoadBitmap(IDB_BITMAP1);
  else
   pBitmap->LoadBitmap(IDB_BITMAP2);
  rtButton = m_rtButtExit;
  rtButton.OffsetRect(-rtWnd.left, -rtWnd.top);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButton.left, rtButton.top, rtButton.Width(), rtButton.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  pBitmap->DeleteObject();

  //最大化/恢复button
  if (m_rtButtMax.PtInRect(point))
  {
   if (IsZoomed())
    pBitmap->LoadBitmap(IDB_BITMAP9);
   else
    pBitmap->LoadBitmap(IDB_BITMAP5);
  }
  else
  {
   if (IsZoomed())
    pBitmap->LoadBitmap(IDB_BITMAP10);
   else
    pBitmap->LoadBitmap(IDB_BITMAP6);
  }
  rtButton = m_rtButtMax;
  rtButton.OffsetRect(-rtWnd.left, -rtWnd.top);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButton.left, rtButton.top, rtButton.Width(), rtButton.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  pBitmap->DeleteObject();

  //最小化button
  if (m_rtButtMin.PtInRect(point))
   pBitmap->LoadBitmap(IDB_BITMAP7);
  else
   pBitmap->LoadBitmap(IDB_BITMAP8);
  rtButton = m_rtButtMin;
  rtButton.OffsetRect(-rtWnd.left, -rtWnd.top);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButton.left, rtButton.top, rtButton.Width(), rtButton.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  pBitmap->DeleteObject();

 }

 pDisplayMemDC->DeleteDC();

 delete pDisplayMemDC;
 delete pBitmap;

 //CDialog::OnNcMouseMove(nHitTest, point);
 CFrameWndEx::OnNcMouseMove(nHitTest, point);
}

 

 


BOOL CMainFrame::OnEraseBkgnd(CDC* pDC)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值

 BOOL retValue= CWnd::OnEraseBkgnd(pDC);

 CRect rc;
 GetClientRect(&rc);
 pDC->FillSolidRect(&rc,RGB(236,233,216));

 return retValue;
}


 


BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
 // TODO: 在此添加专用代码和/或调用基类

if(pMsg->message == WM_KEYDOWN){        
  switch(pMsg->wParam){
  case VK_RETURN://截获回车
   return TRUE;
  case VK_ESCAPE://截获ESC
   return TRUE;
   break;
  }
 }

 return CFrameWndEx::PreTranslateMessage(pMsg);
}


LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // TODO: 在此添加专用代码和/或调用基类
 LRESULT lrst=CWnd::DefWindowProc(message, wParam, lParam);
/*
  IsWindow()函数用法:
 IsWindow()函数判断hwndDlg是否已经指向一个窗口,如果返回TRUE,表示对话框已经显示,
 不需要再调用对话框,如果返回FALSE,调用CreateDialog()显示对话框。要注意一点,
 hwndDlg必须声明为全局变量,而不是对话框函数的私有变量,否则每次对话框函数被调用都将重新初始化
 该变量IsWindow(hwndDlg)总方会FALSE,上面的判断语句就形同虚设了。同时应在调用EndDialog()前设hwndDlg=NULL,
 否则对话框关闭后IsWindow(hwndDlg)总返回TRUE,再也打不开了*/

 if (!::IsWindow(m_hWnd))
  return lrst;
 
 if (message==WM_MOVE||message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY)
 {
  try
  {
   CDC* pWinDC = GetWindowDC();
   if (pWinDC)
    DrawTitleBar(pWinDC);
   ReleaseDC(pWinDC);
  }
  catch( CException* e )
  {
   e->Delete();
  }
 }
 return lrst;
 //return CFrameWndEx::DefWindowProc(message, wParam, lParam);
}
void CMainFrame::DrawTitleBar(CDC *pDC)
{
 if (m_hWnd)
 {
  CBrush Brush(RGB(83,83,83));
  CBrush* pOldBrush = pDC->SelectObject(&Brush);

  CRect rtWnd, rtTitle, rtButtons;
  GetWindowRect(&rtWnd);

  //取得标题栏的位置
  //SM_CXFRAME 窗口边框的边缘宽度
  //SM_CYFRAME 窗口边框的边缘高度
  //SM_CXSIZE  窗口标题栏宽度
  //SM_CYSIZE  窗口标题栏高度
  rtTitle.left = GetSystemMetrics(SM_CXFRAME);
  rtTitle.top = GetSystemMetrics(SM_CYFRAME); 
  rtTitle.right = rtWnd.right - rtWnd.left - GetSystemMetrics(SM_CXFRAME);
  rtTitle.bottom = rtTitle.top + GetSystemMetrics(SM_CYSIZE);

  CPoint point;
  //填充顶部框架
  point.x = rtWnd.Width();      
  point.y = GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYFRAME) + 0;
  pDC->PatBlt(0, 0, point.x, point.y, PATCOPY);
  //填充左侧框架
  point.x = GetSystemMetrics(SM_CXFRAME) -1;
  point.y = rtWnd.Height()- 1;
  pDC->PatBlt(0, 0, point.x, point.y, PATCOPY);
  //填充底部框架
  point.x = rtWnd.Width();
  point.y = GetSystemMetrics(SM_CYFRAME);
  pDC->PatBlt(0, rtWnd.Height()-point.y, point.x, point.y, PATCOPY);
  //填充右侧框架
  point.x = GetSystemMetrics(SM_CXFRAME);
  point.y = rtWnd.Height();
  pDC->PatBlt(rtWnd.Width()-point.x, 0, point.x, point.y, PATCOPY);


  //重画标题栏图标
  m_rtIcon.left = rtTitle.left ;
  m_rtIcon.top = rtTitle.top;
  m_rtIcon.right = m_rtIcon.left + 16;
  m_rtIcon.bottom = m_rtIcon.top + 15;
  ::DrawIconEx(pDC->m_hDC, m_rtIcon.left, m_rtIcon.top,  AfxGetApp()->LoadIcon(IDI_ICON1),
   m_rtIcon.Width(), m_rtIcon.Height(), 0, NULL, DI_NORMAL);
  m_rtIcon.OffsetRect(rtWnd.TopLeft());

  CBitmap* pBitmap = new CBitmap;
  CBitmap* pOldBitmap;
  CDC* pDisplayMemDC=new CDC;
  pDisplayMemDC->CreateCompatibleDC(pDC);

  //重画关闭button
  rtButtons.left = rtTitle.right - 16;
  rtButtons.top = rtTitle.top - 1;
  rtButtons.right = rtButtons.left + 16;
  rtButtons.bottom = rtButtons.top + 15;
  pBitmap->LoadBitmap(IDB_BITMAP1);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButtons.left, rtButtons.top, rtButtons.Width(), rtButtons.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  m_rtButtExit = rtButtons;
  m_rtButtExit.OffsetRect(rtWnd.TopLeft());
  pBitmap->DeleteObject();

  //重画最大化/恢复button
  rtButtons.right = rtButtons.left - 3;
  rtButtons.left = rtButtons.right - 16;
  if (IsZoomed())
   pBitmap->LoadBitmap(IDB_BITMAP10);
  else
   pBitmap->LoadBitmap(IDB_BITMAP5);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButtons.left, rtButtons.top, rtButtons.Width(), rtButtons.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  m_rtButtMax = rtButtons;
  m_rtButtMax.OffsetRect(rtWnd.TopLeft());
  pBitmap->DeleteObject();

  //重画最小化button
  rtButtons.right = rtButtons.left - 3;
  rtButtons.left = rtButtons.right - 16;
  pBitmap->LoadBitmap(IDB_BITMAP7);
  pOldBitmap=(CBitmap*)pDisplayMemDC->SelectObject(pBitmap);
  pDC->BitBlt(rtButtons.left, rtButtons.top, rtButtons.Width(), rtButtons.Height(), pDisplayMemDC, 0, 0, SRCCOPY);
  pDisplayMemDC->SelectObject(pOldBitmap);
  m_rtButtMin = rtButtons;
  m_rtButtMin.OffsetRect(rtWnd.TopLeft());
  pBitmap->DeleteObject();

  //重画caption
  int nOldMode = pDC->SetBkMode(TRANSPARENT);
  COLORREF clOldText=pDC->SetTextColor(RGB(255, 255, 255));

  CFont m_captionFont;
  m_captionFont.CreateFont(
   18,                        // 字体的高度   
   0,                         // 字体的宽度
   0,                         // 字体显示的角度
   0,                         // 字体的角度
   FW_BOLD,                   // 字体的磅数
   FALSE,                     // 斜体字体
   FALSE,                     // 带下划线的字体
   0,                         // 带删除线的字体
   ANSI_CHARSET,              // 所需的字符集
   OUT_DEFAULT_PRECIS,        // 输出的精度
   CLIP_DEFAULT_PRECIS,       // 裁减的精度
   DEFAULT_QUALITY,           // 逻辑字体与输出设备的实际字体之间的精度
   DEFAULT_PITCH | FF_SWISS,  // 字体间距和字体集
   _T("Arial"));              // 字体名称

  CFont* pOldFont = NULL;   
  pOldFont = pDC->SelectObject(&m_captionFont);

  rtTitle.left += m_rtIcon.Width ()+3;
  rtTitle.top = rtTitle.top;
  rtTitle.bottom = rtTitle.top + 30;
  CString m_strTitle;
  GetWindowText(m_strTitle);
  pDC->DrawText(m_strTitle, &rtTitle, DT_LEFT);
  pDC->SetBkMode(nOldMode);
  pDC->SetTextColor(clOldText);

  ReleaseDC(pDisplayMemDC);
  delete pDisplayMemDC;
  delete pBitmap;
 }
}

 

客户自绘wtl版本指的是在Windows模板库(WTL)基础上通过自主绘制非客户来定制界面的版本。 WTL是一个开源的C++模板库,用于简化Windows桌面应用程序的开发。它相较于MFC更轻量级,更容易学习和使用。WTL提供了一系列的模板类和宏,可以快速开发具有Windows UI风格的应用程序。 在WTL中,非客户(Non-Client Area)是指窗口边框以及标题栏、菜单栏、状态栏等装饰性的部分。传统上,这部分通常由操作系统负责绘制和管理。但是对于一些特殊需求,比如自定义的窗口样式、非矩形窗口等,我们需要对非客户进行自主绘制。 非客户自绘wtl版本即是基于WTL框架,在需要自定义非客户的情况下,通过手动绘制实现。这种方式需要重载WTL框架中的非客户绘制相关的函数,比如`OnNcPaint()`、`OnNcCalcSize()`等,来处理非客户的绘制逻辑。 非客户自绘wtl版本的好处在于可以完全控制非客户的外观。可以根据自己的需要,实现各种特殊的样式和效果,如渐变色、图案填充、自定义按钮等。这样可以使应用程序更加美观和独特,增强用户体验。 但是非客户自绘wtl版本也存在一些挑战。首先,自绘非客户需要较高的绘制技术和图形处理能力。其次,自绘非客户还会涉及到一些与系统相关的问题,如窗口移动、窗口关闭等操作的处理。因此,需要对WTL框架有较深入的理解和熟练的编程技巧。 总之,非客户自绘wtl版本是在WTL框架基础上,通过自主绘制实现自定义非客户的一种方式。它可以让我们灵活控制非客户的外观,提升应用程序的美观程度和用户体验。然而,也需要考虑到相关的技术和系统问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值