MFC窗口有标题栏和边框的时候,重绘不是很方便,在OnNcPaint中重绘标题栏如果调用基类的OnNcPaint,自己的后面的重绘都不生效,如果不调用基类的OnNcPaint,win10上的mfc程序出现了win7风格的边框,而且宽度还不能控制。
移除边框
DWORD dw = ::GetWindowLong(GetSafeHwnd(), GWL_STYLE);
dw = dw & ~WS_CAPTION;//取消标题栏
dw = dw & ~WS_THICKFRAME;//取消拖动改变大小//不取消的话,自绘标题栏上面会有一条白边而且覆盖不了
::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dw);
去除标题栏之后就要自绘标题栏了
步骤如下
1.去除边框标题栏
2.重新设置标题栏、边框大小(OnNcCalcSize)
3.设定标题栏响应区域(OnNcHitTest)
4.重绘(多个地方需要重绘,但是可以调用统一绘制方法WM_MOVE、WM_PAINT、WM_NCPAINT、WM_NCACTIVATE、WM_NOTIFY)
DWORD dw = ::GetWindowLong(GetSafeHwnd(), GWL_STYLE);
dw = dw & ~WS_CAPTION;//取消标题栏
dw = dw & ~WS_THICKFRAME;//取消拖动改变大小//不取消的话,自绘标题栏上面会有一条白边而且覆盖不了
::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dw);
//取消边框内的边缘,也就是取消3D效果
dw = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
dw = dw & ~WS_EX_DLGMODALFRAME;
dw = dw & ~WS_EX_CLIENTEDGE;
dw = dw & ~WS_EX_WINDOWEDGE;
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, dw);
//建议使用成员变量的方式存储各个属性
void videoDialog::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
int nTitleHeight = 40;
int nFrameBorerL = 1;
int nFrameBorerR = 1;
int nFrameBorerB = 1;
lpncsp->rgrc[0].top += nTitleHeight;
lpncsp->rgrc[0].left += nFrameBorerL;
lpncsp->rgrc[0].right -= nFrameBorerR;
lpncsp->rgrc[0].bottom -= nFrameBorerB;
CDialogEx::OnNcCalcSize(bCalcValidRects, lpncsp);
}
OnNcCalcSize第0个元素的初始值是窗口大小,说是计算NcSize,实际上是设置客户区大小,多余的就是non-client的size
top就是标题栏的高度,也就是窗口top距离client-top的距离,其他就是左边距、右边距、下边距
//建议使用成员变量,标题栏高度:40
LRESULT videoDialog::OnNcHitTest(CPoint point)
{
RECT rectWindows, rectClient;
this->GetWindowRect(&rectWindows);
this->GetClientRect(&rectClient);
if (point.y > rectWindows.top && point.y < rectWindows.top + 40)
{
return HTCAPTION;//标题栏形式
}
else
{
return CDialogEx::OnNcHitTest(point);
}
}
这里就是当窗口发生事件时,计算当前坐标属于什么区域,高度40以内返回标题栏区域,就可以在重绘标题栏的基础上用标题栏拖动窗口了
LRESULT videoDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
//以下消息可能使标题栏发生重绘,所以重新绘制,也可以响应标题栏处的鼠标移动、点击事件,
if (message == WM_MOVE || message == WM_PAINT || message == WM_NCPAINT || message == WM_NCACTIVATE || message == WM_NOTIFY)
{
CDC* pWinDC = GetWindowDC();
if (pWinDC)
DrawTitleBar(pWinDC);
ReleaseDC(pWinDC);
}
return CDialogEx::DefWindowProc(message, wParam, lParam);
}
void videoDialog::DrawTitleBar(CDC *pDC)
{
if (m_hWnd)
{
CBrush Brush(RGB(0xff, 0x63, 0x21));
CBrush* pOldBrush = pDC->SelectObject(&Brush);
CRect rtWnd, rtTitle, rtButtons;
GetWindowRect(&rtWnd);
//取得标题栏的位置
rtTitle.left = 0;// GetSystemMetrics(SM_CXFRAME);
rtTitle.top = 0;
rtTitle.right = rtWnd.right - rtWnd.left;// -GetSystemMetrics(SM_CXFRAME);
rtTitle.bottom = rtTitle.top + 40;
CPoint point;
//填充顶部框架
point.x = rtWnd.Width();
point.y = 0;
pDC->PatBlt(0, 0, point.x, point.y, PATCOPY);
//填充左侧框架
point.x = GetSystemMetrics(SM_CXFRAME);
point.y = rtWnd.Height();
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);
pDC->SelectObject(pOldBrush);
//重写标题文字
int nOldMode = pDC->SetBkMode(TRANSPARENT);
COLORREF clOldText = pDC->SetTextColor(RGB(255, 255, 255));
pDC->SelectStockObject(SYSTEM_FIXED_FONT);
CBrush b(RGB(0xd8, 0xd8, 0xd8));
pDC->FillRect(&rtTitle, &b);
CString m_strTitle;
GetWindowText(m_strTitle);
pDC->SetTextColor(clOldText);
pDC->DrawText(m_strTitle, &rtTitle, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
pDC->SetBkMode(nOldMode);
}
}
效果图:
fuck,一上传就卡死,反正亲测通过