⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 自绘边框窗口.txt

📁 用来自绘边框窗口
💻 TXT
字号:
自绘边框窗口 

代码:自绘窗口需要响应如下的几个消息: 
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了。 
 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -