MFC自绘标题栏和边框

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)

1.去除标题栏

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);

2.设置标题栏、边框大小

//建议使用成员变量的方式存储各个属性
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的距离,其他就是左边距、右边距、下边距

3.设置标题栏响应区域

//建议使用成员变量,标题栏高度: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以内返回标题栏区域,就可以在重绘标题栏的基础上用标题栏拖动窗口了

4.重绘

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,一上传就卡死,反正亲测通过

你可能感兴趣的:(mfc)