自绘窗口需要响应如下的几个消息:
1、WM_NCCALCSIZE     
这个是用来返回NC区域的。windows系统根据这个消息的返回,决定矩形区域中,NC区域在哪里。如下的代码是一个实现:    
void CSIPanel::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)    
{    
   RECT r;    
   // TODO: Add your message handler code here and/or call default    
   if (m_psi)    
   {    
      if (m_psi->m_bCustomWindow)    
      {     
          memcpy(&r,&lpncsp->rgrc[0],sizeof(RECT));    
          r.top = r.top+m_psi->m_NcRect.top;    
          r.bottom = r.bottom - m_psi->m_NcRect.bottom;    
          r.left = r.left+m_psi->m_NcRect.left;    
          r.right = r.right-m_psi->m_NcRect.right;    
          memcpy(&lpncsp->rgrc[0],&r,sizeof(RECT));    
          return;    
       }    
   }    
   CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);    
}    
在这个代码中,m_psi->m_bCustomWindow是用来标志是否是自绘窗口的。如果不是自绘窗口,才需要调整大小。至于bCalcValidRects这个参数,说老实话我也不知道它的用处。我查过很多的代码,都没有使用这个参数(比如BCGPRO的代码等),而实际情况下也是不使用也没有问题的。完全只需要更改lpncsp->rgrc[0]就可以了。
2、需要响应NCPAINT消息     
(如果在窗口非active的情况下,并不绘制ncpaint或者调用原来的ncpaint,那么系统就会画出以前的难看的窗口边框和标题)很简单,代码:    
void CSIPanel::OnNcPaint()    
{    
   CWindowDC dc(this);    
   if (m_psi == NULL)    
      return;    
   if (m_psi->m_bCustomWindow == FALSE)    
      return;    
   p_PaintCorners(&dc);    
   p_PaintIcons(&dc);    
   p_PaintPushedIcons(&dc);    
   p_PaintTitleLine(&dc);    
}
3、还需要响应CREATE消息     
为何响应Create消息?因为窗口是不规则的(不是直角矩形而是园角矩形的)    
int CSIPanel::OnCreate(LPCREATESTRUCT lpCreateStruct)    
{    
   if (CWnd::OnCreate(lpCreateStruct) == -1)    
      return -1;    
   // TODO: Add your specialized creation code here    
   ResetWindowRgn();    
   SetWindowPos(NULL,0,0,0,0,SWP_FRAMECHANGED|SWP_NOOWNERZORDER|    
         SWP_NOMOVE|SWP_NOSIZE);    
   return 0;    
}    
SetWindowPos是强制让Window重新计算大小(NCCALCSIZE)和绘制。     
/////////////////////////////////////////////////////////////////////////////    
// CSIPanel message handlers    
void CSIPanel::ResetWindowRgn()    
{    
   int iRet;    
   BOOL bRet;    
   CRgn m_rgn1,m_rgn2,m_rgn3;    
   RECT r;    
   GetWindowRect(&r);    
   OffsetRect(&r,-r.left,-r.top);    
   bRet = m_rgn1.CreateRoundRectRgn(r.left,r.top,r.right+1,r.top+45,12,12);    
   m_rgn2.CreateRoundRectRgn(r.left,r.top+18,r.right+1,r.bottom+2,12,12);    
   iRet = m_rgn2.CombineRgn(&m_rgn1,&m_rgn2,RGN_OR);    
   iRet = SetWindowRgn(m_rgn2,TRUE);    
}
4、还需要响应WM_SIZE     
void CSIPanel::OnSize(UINT nType, int cx, int cy)    
{    
   CWnd::OnSize(nType, cx, cy);    
   // TODO: Add your message handler code here    
   ResetWindowRgn();    
   Invalidate();    
}
5、响应ACTIVE     
用于绘制不同情况下的标题    
void CSIPanel::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)    
{    
   CWnd::OnActivate(nState, pWndOther, bMinimized);    
   if (nState == WA_INACTIVE)    
   {    
      if (m_bTraceFlag)    
      {    
         ReleaseCapture();    
         m_bTraceFlag = FALSE;    
      }    
      m_bActive = FALSE;    
   }    
   else    
      m_bActive = TRUE;    
   SetWindowPos(NULL,0,0,0,0,SWP_FRAMECHANGED|SWP_NOOWNERZORDER|    
        SWP_NOMOVE|SWP_NOSIZE);    
}    
这里为何要检测一个鼠标的情况呢?因为如果在标题行上有自绘的小按钮,那么,我们需要跟踪鼠标才行(响应NCMOUSELCLICK是不行的)所以,如果本窗口失去焦点,应该RelaseCapture。
6、响应NCLBUTTONDOWN     
为了能够在标题行绘制自己的最大最小按钮,并且能够响应它,就绪要响应在标题行上的鼠标左键。但是为了能够像window操作一样,鼠标左键按下的时候不触发,而是鼠标左键抬起的时候触发,这就需要在NCLBUTTONDOWN的时候做SetCapture.    
void CSIPanel::OnNcLButtonDown(UINT nHitTest, CPoint point)    
{    
   // TODO: Add your message handler code here and/or call default    
   RECT r;    
   RECT r1;    
   BOOL bRet;    
   int iSizeX,iSizeY;
   if (m_bTraceFlag == TRUE)   
      return;    
   m_bMinPushed = FALSE;    
   m_bMaxPushed = FALSE;    
   m_bClosePushed = FALSE;    
   m_bSysPushed = FALSE;    
   GetWindowRect(&r);    
   if (m_bActive == FALSE)    
      goto L_DEFAULT;    
   r.bottom = r.top + (m_psi->m_rLT.bottom - m_psi->m_rLT.top);    
   bRet = PtInRect(&r,point);    
   if (bRet == FALSE)    
      goto L_DEFAULT;    
   /* ----------------------------------------------------------    
   * 判定是否在按钮上按下的.    
   * ---------------------------------------------------------- */    
   if (m_bIconSys)    
   {    
      r1.left = r.left + 5;    
      r1.top = r.top + 5;    
      r1.right = m_psi->m_rSYS.right - m_psi->m_rSYS.left + r1.left;    
      r1.bottom = m_psi->m_rSYS.bottom- m_psi->m_rSYS.top + r1.top;    
      bRet = PtInRect(&r1,point);    
      if (bRet == TRUE)    
     {    
         m_bSysPushed = TRUE;    
         goto L_FOUND;    
      }    
   }    
   if (m_bIconMin)    
   {    
      iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
      iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
      r1.left = r.right - 6 - 3 * iSizeX - 3 * 2;    
      r1.top = r.top+5;    
      r1.right = r1.left + iSizeX;    
      r1.bottom = r1.top + iSizeY;    
      bRet = PtInRect(&r1,point);    
      if (bRet == TRUE)    
      {    
         m_bMinPushed= TRUE;    
         goto L_FOUND;    
      }    
   }    
   if (m_bIconMax)    
   {    
      iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
      iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
      r1.left = r.right - 6 - 2 * iSizeX - 2 * 2;    
      r1.top = r.top+5;    
      r1.right = r1.left + iSizeX;    
      r1.bottom = r1.top + iSizeY;    
      bRet = PtInRect(&r1,point);    
      if (bRet == TRUE)    
      {    
         m_bMaxPushed= TRUE;    
         goto L_FOUND;    
      }    
   }    
   if (m_bIconClose)    
   {    
      iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
      iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
      r1.left = r.right - 6 - iSizeX - 2;    
      r1.top = r.top+5;    
      r1.right = r1.left + iSizeX;    
      r1.bottom = r1.top + iSizeY;    
      bRet = PtInRect(&r1,point);    
      if (bRet == TRUE)    
      {    
         m_bClosePushed= TRUE;    
         goto L_FOUND;    
      }    
   }    
L_DEFAULT:    
   CWnd::OnNcLButtonDown(nHitTest, point);    
   return;    
L_FOUND:    
   m_bTraceFlag = TRUE;    
   SetCapture();    
   RepaintIcons();    
   return;    
}
7、当然要响应LBUTTONUP消息     
为何是LBUTTONUP而不是NCLBUTTONUP?因为在NCLBUTTONDOWN的时候SetCapture之后,就是LBUTTONUP消息了。(应该不会有NCLBUTTONUP消息的)。    
void CSIPanel::OnLButtonUp(UINT nFlags, CPoint point)    
{    
   // TODO: Add your message handler code here and/or call default    
   RECT r;    
   CWnd::OnLButtonUp(nFlags, point);    
   if (m_bTraceFlag == FALSE)    
      return;    
   ReleaseCapture();    
   GetWindowRect(&r);    
   m_bTraceFlag = FALSE;    
   if (m_bSysPushed == TRUE)    
   {    
      // PostMessage(WM_SYSCOMMAND,SC_MOUSEMENU,r.left<<16|r.top);    
     PostMessage(WM_SYSCOMMAND,SC_KEYMENU,r.left<<16|r.top);    
   }    
   else if (m_bMinPushed == TRUE)    
   {    
      PostMessage(WM_SYSCOMMAND,SC_MINIMIZE,r.left<<16|r.top);    
   }    
   else if (m_bMaxPushed == TRUE)    
   {    
      PostMessage(WM_SYSCOMMAND,SC_MAXIMIZE,r.left<<16|r.top);    
   }    
   else if (m_bClosePushed == TRUE)    
   {    
      PostMessage(WM_SYSCOMMAND,SC_CLOSE,r.left<<16|r.top);    
   }    
   m_bMinPushed = FALSE;     
   m_bMaxPushed = FALSE;    
   m_bClosePushed = FALSE;    
   m_bSysPushed = FALSE;    
}
8、剩下的就是响应MOUSEMOVE     
为何响应MOUSEMOVE?因为我们注意到,普通windows按钮的性格是按下的时候BUTTON PUSHED,保持鼠标左键按下,移开鼠标的时候BUTTON UP,然后再到这个BUTTON上抬起鼠标左键才触发,为了能做的差不多像,我们有:    
void CSIPanel::OnMouseMove(UINT nFlags, CPoint px)    
{    
 // TODO: Add your message handler code here and/or call default    
 RECT r,r1,rc;    
 BOOL bRet;    
 int iSizeX,iSizeY;    
 POINT point;    
 CWnd::OnMouseMove(nFlags, px);    
 if (m_bTraceFlag == FALSE)    
 return;    
 GetWindowRect(&r);    
 GetClientRect(&rc);    
 ClientToScreen(&rc);    
 point.x = rc.left + px.x;    
 point.y = rc.top + px.y;    
 /* ----------------------------------------------------------    
 * 判定是否在按钮上按下的.    
 * ---------------------------------------------------------- */    
 if (m_bIconSys)    
 {    
 r1.left = r.left + 5;    
 r1.top = r.top + 5;    
 r1.right = m_psi->m_rSYS.right - m_psi->m_rSYS.left + r1.left;    
 r1.bottom = m_psi->m_rSYS.bottom- m_psi->m_rSYS.top + r1.top;    
 bRet = PtInRect(&r1,point);    
 if (bRet == TRUE)    
 {    
 m_bSysPushed = TRUE;    
 goto L_FOUND;    
 }    
 }    
 if (m_bIconMin)    
 {    
 iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
 iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
 r1.left = r.right - 6 - 3 * iSizeX - 3 * 2;    
 r1.top = r.top+5;    
 r1.right = r1.left + iSizeX;    
 r1.bottom = r1.top + iSizeY;    
 bRet = PtInRect(&r1,point);    
 if (bRet == TRUE)    
 {    
 m_bMinPushed= TRUE;    
 goto L_FOUND;    
 }    
 }    
 if (m_bIconMax)    
 {    
 iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
 iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
 r1.left = r.right - 6 - 2 * iSizeX - 2 * 2;    
 r1.top = r.top+5;    
 r1.right = r1.left + iSizeX;    
 r1.bottom = r1.top + iSizeY;    
 bRet = PtInRect(&r1,point);    
 if (bRet == TRUE)    
 {    
 m_bMaxPushed= TRUE;    
 goto L_FOUND;    
 }    
 }    
 if (m_bIconClose)    
 {    
 iSizeX = m_psi->m_rCLOSE.right - m_psi->m_rCLOSE.left;    
 iSizeY = m_psi->m_rCLOSE.bottom - m_psi->m_rCLOSE.top;    
 r1.left = r.right - 6 - iSizeX - 2;    
 r1.top = r.top+5;    
 r1.right = r1.left + iSizeX;    
 r1.bottom = r1.top + iSizeY;    
 bRet = PtInRect(&r1,point);    
 if (bRet == TRUE)    
 {    
 m_bClosePushed= TRUE;    
 goto L_FOUND;    
 }    
 }    
 m_bMinPushed = FALSE;    
 m_bMaxPushed = FALSE;    
 m_bClosePushed = FALSE;    
 m_bSysPushed = FALSE;    
L_FOUND:    
 RepaintIcons();    
 return;    
}    
恩。到这里,自绘边框的窗口就ok了。  
                    
                
                
            
        
浙公网安备 33010602011771号