VC 实现 自绘 窗体 标题栏 非客户区
2008-12-13 11:11
417 查看
VC 实现 自绘 窗体 标题栏 非客户区 本程序在VC03测试成功,效果, 图片素材:从BC1.bmp到第2页的UR_N.bmp 1.准备工作。 (1)得到文件夹中的位图句柄: 首先要准备相应图片。 HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//Test.bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); CBitmap cbmp; cbmp.Attach(bitmap); 其中,skin//Test.bmp为文件路径。 (2)关于非客户区的消息: ON_WM_NCPAINT()//绘非客户区时。 ON_WM_NCACTIVATE()//非客户区有焦点和失去焦点时。 ON_WM_NCCALCSIZE()//计算窗体尺寸时。 (3)改变标题栏尺寸: 重写ON_WM_NCCALCSIZE()消息响应函数。 void CMYSkinDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) { //重设标题栏高度。m_nCaptionHeight在PreSubclassWindow中计算。 lpncsp->rgrc[0].top+=m_nCaptionHeight-GetSystemMetrics(SM_CYCAPTION); CDialog::OnNcCalcSize(bCalcValidRects, lpncsp); } (4)非客户区的鼠标动作: 相关消息: ON_WM_NCLBUTTONDOWN()//鼠标下。 ON_WM_NCLBUTTONUP()//鼠标上。 ON_WM_NCMOUSEMOVE()//鼠标悬停。 (5)屏蔽最大最小关闭消息: 在WindowProc中: LRESULT CMYSkinDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_NCHITTEST) { LRESULT lRet = CDialog::WindowProc(message, wParam, lParam); //屏蔽最大最小关闭消息. if (lRet==HTZOOM || lRet == HTMINBUTTON || lRet == HTCLOSE) return HTCAPTION;//视为标题栏动作。 else return lRet; } 2.程序和注释: (1)用户变量和函数. protected: CBrush m_brBG;//对话框背景颜色,在OnInitDialog 中初始化,在OnCtlColor中作为返回值. CString m_strCaption;//标题. CRect m_rtWnd;//整个窗体Rect. int m_nCaptionHeight;//标题栏高度. CRect m_rtButtons;//最大,最小,关闭按钮. CRect m_rtIcon;//图标. CRect m_rtButtMin;//最小. CRect m_rtButtMax;//最大. CRect m_rtButtExit;//关闭. CRect m_rtButtMaxM; CRect m_rtButtMinM; CRect m_rtButtExitM; CRect m_bmRt;//Bitmap所在的Rect. BOOL m_bNCActive;//窗体活动. bool FillRtWithBmp(CString bmpFileName,CDC *pDC,CRect rt);//用Bitmap添满整个rt. bool FillWithBmpRtUL(CString bmpFileName,CDC *pDC,CPoint pt);//pt为Bitmap的左上. bool FillWithBmpRtUR(CString bmpFileName,CDC *pDC, CPoint pt);//pt为Bitmap的右上. bool FillButton(CString bmpButtonName, CDC *pDC, CPoint pt,int intState);// void DrawNC(CDC* pDC);//画非客户区. (2)显示之前计算从图片计算标题栏高度: void CMYSkinDlg::PreSubclassWindow() { //得到标题栏图片高度。 CString bmpFileName="C2"; HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpFileName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); cbmp.DeleteObject(); m_nCaptionHeight=bm.bmHeight-4; CDialog::PreSubclassWindow(); } (3)重写OnNcCalCsize: void CMYSkinDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) { //重设标题栏高度。m_nCaptionHeight在PreSubclassWindow中计算。 lpncsp->rgrc[0].top+=m_nCaptionHeight-GetSystemMetrics(SM_CYCAPTION); CDialog::OnNcCalcSize(bCalcValidRects, lpncsp); } (4)绘非客户区: void CMYSkinDlg::OnNcPaint() { CDC* pWinDC=GetWindowDC(); if (pWinDC) DrawNC(pWinDC);//函数实现略。 ReleaseDC(pWinDC); } (5)对非客户区焦点情况的处理: BOOL CMYSkinDlg::OnNcActivate(BOOL bActive) { m_bNCActive=bActive;//在DrawNC中有体现。//初始时设NC区为活动. //防止在任务栏右键图标时出现最大最小关闭 OnNcPaint();//实际源程序中有细节的考虑。 return true; } (6)响应鼠标在非客户区的事件: 鼠标在非客户区按下: void CMYSkinDlg::OnNcLButtonDown(UINT nHitTest, CPoint point) { //检测最小,最大和关闭按钮是否按下,然后更换图片. if(!IsZoomed())//防止在最大化后能拖动. CDialog::OnNcLButtonDown(nHitTest,point); } //OnNcLButtonUp中触发最大最小关闭: void CMYSkinDlg::OnNcLButtonUp(UINT nHitTest, CPoint point) { 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)); else SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y) ); } } //鼠标在非客户区悬停: void CMYSkinDlg::OnNcMouseMove(UINT nHitTest, CPoint point) { //检测最小,最大和关闭按钮是否有鼠标悬停,然后更换相应图片. } (7)屏蔽单击程序非客户系统原有图标矩形时出现的系统菜单或动作: UINT CMYSkinDlg::OnNcHitTest(CPoint point) { CRect tst(2,2,m_nCaptionHeight+4,m_nCaptionHeight+4); tst.OffsetRect(m_rtWnd.TopLeft());//原图标屏幕位置 if(tst.PtInRect(point))//最大最小关闭按钮位置. return HTCAPTION; else if(m_rtButtMin.PtInRect(point)|| m_rtButtMax.PtInRect(point)|| m_rtButtExit.PtInRect(point)) return HTSYSMENU;//使此区域能够响应OnNcLButtonUp else return CDialog::OnNcHitTest(point); } (8)系统菜单的显示和隐藏: 为了使重绘工作顺利进行而不影响程序外在表现,要对系统菜单显示和隐藏, 如在OnNcActivate中有这样的程序片段: if(bActive) { ModifyStyle(0, WS_SYSMENU); OnNcPaint(); } else { ModifyStyle(WS_SYSMENU, 0); OnNcPaint(); } 又如,在OnCreate中: this->ModifyStyle(WS_SYSMENU, 0);//防止在任务栏右单击时出现最大最小关闭. (9)对系统最大最小关闭图标依然出现的处理: 虽然用户取消了NC区系统的重绘,但是系统仍然对最大最小关闭图标重绘(主要表现在用户右单击任务栏图标时),这里的处理方法如下: void CMYSkinDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { //CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); if (bSysMenu) OnNcPaint();//防止在任务栏右键图标时窗口出现最大最小关闭 } 3.源程序: (1)MYSkinDlg.h: ////实现 protected://用户变量和函数. CBrush m_brBG;//对话框背景颜色,在OnInitDialog 中初始化,在OnCtlColor中作为返回值. CString m_strCaption;//标题. CRect m_rtWnd;//整个窗体Rect. int m_nCaptionHeight;//标题栏高度. CRect m_rtButtons;//最大,最小,关闭按钮. CRect m_rtIcon;//图标. CRect m_rtButtMin;//最小. CRect m_rtButtMax;//最大. CRect m_rtButtExit;//关闭. CRect m_rtButtMaxM; CRect m_rtButtMinM; CRect m_rtButtExitM; CRect m_bmRt;//Bitmap所在的Rect. BOOL m_bNCActive;//窗体活动. bool FillRtWithBmp(CString bmpFileName,CDC *pDC,CRect rt);//用Bitmap添满整个rt. bool FillWithBmpRtUL(CString bmpFileName,CDC *pDC,CPoint pt);//pt为Bitmap的左上. bool FillWithBmpRtUR(CString bmpFileName,CDC *pDC, CPoint pt);//pt为Bitmap的右上. bool FillButton(CString bmpButtonName, CDC *pDC, CPoint pt,int intState);// void DrawNC(CDC* pDC);//画非客户区. (2)MYSkinDlg.cpp: // MYSkinDlg.cpp : 实现文件 #include "stdafx.h" #include "MYSkin.h" #include "MYSkinDlg.h" #include ".\myskindlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMYSkinDlg 对话框 CMYSkinDlg::CMYSkinDlg(CWnd* pParent /*=NULL*/) : CDialog(CMYSkinDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMYSkinDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMYSkinDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON, OnBnClickedButton) ON_WM_NCPAINT() ON_WM_NCACTIVATE() ON_WM_NCCALCSIZE() ON_WM_NCHITTEST() ON_WM_NCLBUTTONDOWN() ON_WM_NCLBUTTONUP() ON_WM_MOVE() ON_WM_CREATE() ON_WM_INITMENUPOPUP() ON_WM_NCMOUSEMOVE() ON_WM_CTLCOLOR() END_MESSAGE_MAP() // CMYSkinDlg 消息处理程序 BOOL CMYSkinDlg::OnInitDialog() { CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 m_bNCActive=true;//初始NC区为活动. m_brBG.CreateSolidBrush(RGB(220, 220, 220)); //对话框背景颜色,在OnCtlColor中作为返回值. return TRUE; // 除非设置了控件的焦点,否则返回 TRUE } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMYSkinDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标显示。 HCURSOR CMYSkinDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CMYSkinDlg::OnBnClickedButton() { MessageBox("Main Dlg Lost Focus!!"); } ///////////////////////////////////////////////////////////////////////////////////// void CMYSkinDlg::OnNcPaint() { CDC* pWinDC=GetWindowDC(); if (pWinDC) DrawNC(pWinDC); ReleaseDC(pWinDC); } BOOL CMYSkinDlg::OnNcActivate(BOOL bActive) { m_bNCActive=bActive; //防止在任务栏右键图标时出现最大最小关闭 if(bActive) { ModifyStyle(0, WS_SYSMENU); OnNcPaint(); } else { ModifyStyle(WS_SYSMENU, 0); OnNcPaint(); } return true; } void CMYSkinDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) { //重设标题栏高度。m_nCaptionHeight在PreSubclassWindow中计算。 lpncsp->rgrc[0].top+=m_nCaptionHeight-GetSystemMetrics(SM_CYCAPTION); CDialog::OnNcCalcSize(bCalcValidRects, lpncsp); } UINT CMYSkinDlg::OnNcHitTest(CPoint point) { CRect tst(2,2,m_nCaptionHeight+4,m_nCaptionHeight+4); tst.OffsetRect(m_rtWnd.TopLeft());//原图标屏幕位置 if(tst.PtInRect(point))//最大最小关闭按钮位置. return HTCAPTION; else if(m_rtButtMin.PtInRect(point)|| m_rtButtMax.PtInRect(point)|| m_rtButtExit.PtInRect(point)) return HTSYSMENU;//使此区域能够响应OnNcLButtonUp else return CDialog::OnNcHitTest(point); } void CMYSkinDlg::OnNcLButtonDown(UINT nHitTest, CPoint point) { //检测最小,最大和关闭按钮是否按下,然后更换. if (m_rtButtExit.PtInRect(point)) { //绘关闭按钮按下时的图标 CDC* pWinDC=GetWindowDC(); FillButton("BTN_CLS",pWinDC,CPoint(m_rtButtExitM.left,m_rtButtExitM.top),3); ReleaseDC(pWinDC); } else if (m_rtButtMin.PtInRect(point)) { //绘最小化按钮按下时的图标 CDC* pWinDC=GetWindowDC(); FillButton("BTN_MIN",pWinDC,CPoint(m_rtButtMinM.left,m_rtButtMinM.top),3); ReleaseDC(pWinDC); } else if (m_rtButtMax.PtInRect(point)) { //绘最大化按钮按下时的图标 CDC* pWinDC=GetWindowDC(); if (IsZoomed()) FillButton("BTN_NOM",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),3); else FillButton("BTN_MAX",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),3); ReleaseDC(pWinDC); } if(!IsZoomed())//防止在最大化后能拖动. CDialog::OnNcLButtonDown(nHitTest,point); } void CMYSkinDlg::OnNcLButtonUp(UINT nHitTest, CPoint point) { 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)); else SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y) ); } } void CMYSkinDlg::OnMove(int x, int y) { CDialog::OnMove(x, y); //OnNcPaint();//减少闪烁,不用OnNcPaint()。 //整个Window的相对于屏幕的矩形 GetWindowRect(&m_rtWnd); //更新窗体矩形. m_rtButtMinM.OffsetRect(m_rtWnd.TopLeft()); //记录最小button屏幕位置 m_rtButtMin=m_rtButtMinM;//记录最小button屏幕位置 m_rtButtMinM.OffsetRect(-m_rtWnd.TopLeft());//还原. m_rtButtMaxM.OffsetRect(m_rtWnd.TopLeft());//记录button屏幕位置 m_rtButtMax=m_rtButtMaxM;//记录button屏幕位置 m_rtButtMaxM.OffsetRect(-m_rtWnd.TopLeft());//还原. m_rtButtExitM.OffsetRect(m_rtWnd.TopLeft());//记录关闭button屏幕位置 m_rtButtExit=m_rtButtExitM;//记录关闭button屏幕位置 m_rtButtExitM.OffsetRect(-m_rtWnd.TopLeft());//还原. } ////////////Bitmap Load Function////////////////////////////////// bool CMYSkinDlg::FillRtWithBmp(CString bmpFileName,CDC *pDC,CRect rt) { //填满整个矩形 HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpFileName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; CDC MemDC; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); MemDC.CreateCompatibleDC (pDC); CBitmap *pOldBitmap=MemDC.SelectObject (&cbmp); CRect rttmp; rttmp=rt; int i=0; int j=0; if(rt.Width()/bm.bmWidth<1 && rt.Height()/bm.bmHeight<1) pDC->BitBlt(rt.left,rt.top,rt.Width(),rt.Height(),&MemDC,0,0,SRCCOPY); else if(rt.Width()/bm.bmWidth<1 && rt.Height()/bm.bmHeight>1) for (j=0; j<=rt.Height()/bm.bmHeight;j++) { pDC->BitBlt(rt.left,rttmp.top,rt.Width(),bm.bmHeight,&MemDC,0,0,SRCCOPY); rttmp.top+=bm.bmHeight; } else if(rt.Width()/bm.bmWidth>1 && rt.Height()/bm.bmHeight<1) for (i=0;i<=rt.Width()/bm.bmWidth;i++) { pDC->BitBlt(rttmp.left,rt.top,bm.bmWidth,rt.Height(),&MemDC,0,0,SRCCOPY); rttmp.left+=bm.bmWidth; } else { for (i=0;i<rt.Width()/bm.bmWidth;i++) { for (j=0; j<rt.Height()/bm.bmHeight;j++) { pDC->BitBlt(rttmp.left,rttmp.top,bm.bmWidth,bm.bmHeight,&MemDC,0,0,SRCCOPY); rttmp.top+=bm.bmHeight; } rttmp.top=rt.top; rttmp.left+=bm.bmWidth; } rttmp=rt; for (i=0;i<rt.Width()/bm.bmWidth;i++) { pDC->BitBlt(rttmp.left, rt.top+rt.Height()-(rt.Height()%bm.bmHeight), bm.bmWidth, rt.Height()%bm.bmHeight, &MemDC,0,0,SRCCOPY); rttmp.left+=bm.bmWidth; } rttmp=rt; for (j=0;j<rt.Height()/bm.bmHeight;j++) { pDC->BitBlt(rt.left+rt.Width()-(rt.Width()%bm.bmWidth), rttmp.top, rt.Width()%bm.bmWidth, bm.bmHeight, &MemDC,0,0,SRCCOPY); rttmp.top+=bm.bmHeight; } rttmp=rt; pDC->BitBlt(rt.left+rt.Width()-(rt.Width()%bm.bmWidth), rt.top+rt.Height()-(rt.Height()%bm.bmHeight), rt.Width()%bm.bmWidth, rt.Height()%bm.bmHeight, &MemDC,0,0,SRCCOPY); } MemDC.SelectObject (pOldBitmap); ReleaseDC(&MemDC); cbmp.DeleteObject(); pOldBitmap->DeleteObject(); return true; } bool CMYSkinDlg::FillWithBmpRtUL(CString bmpFileName,CDC *pDC, CPoint pt) { //只填一张Bitmap.参考点pt为图片左上. HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpFileName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); m_bmRt.left=pt.x;//m_bmRt为全局. m_bmRt.top=pt.y; m_bmRt.right=pt.x + bm.bmWidth; m_bmRt.bottom=pt.y + bm.bmHeight; CDC MemDC; MemDC.CreateCompatibleDC (pDC); CBitmap *pOldBitmap=MemDC.SelectObject (&cbmp); pDC->BitBlt(pt.x,pt.y,pt.x+bm.bmWidth ,pt.y+bm.bmHeight ,&MemDC,0,0,SRCCOPY); MemDC.SelectObject (pOldBitmap); ReleaseDC(&MemDC); cbmp.DeleteObject(); pOldBitmap->DeleteObject(); return true; } bool CMYSkinDlg::FillWithBmpRtUR(CString bmpFileName,CDC *pDC, CPoint pt) { //只填一张图,参考点pt为右上. HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpFileName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); m_bmRt.left=pt.x - bm.bmWidth;//m_bmRt为全局. m_bmRt.top=pt.y; m_bmRt.right=pt.x; m_bmRt.bottom=pt.y + bm.bmHeight; CDC MemDC; MemDC.CreateCompatibleDC (pDC); CBitmap *pOldBitmap=MemDC.SelectObject (&cbmp); pDC->BitBlt(pt.x-bm.bmWidth,pt.y,pt.x,pt.y+bm.bmHeight ,&MemDC,0,0,SRCCOPY); MemDC.SelectObject (pOldBitmap); ReleaseDC(&MemDC); cbmp.DeleteObject(); pOldBitmap->DeleteObject(); return true; } bool CMYSkinDlg::FillButton(CString bmpButtonName, CDC *pDC, CPoint pt,int intState) { HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpButtonName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); CDC MemDC; MemDC.CreateCompatibleDC (pDC); CBitmap *pOldBitmap=MemDC.SelectObject (&cbmp); switch(intState) { case 1: pDC->BitBlt(pt.x, pt.y, bm.bmWidth / 3, bm.bmHeight,&MemDC, 0,0,SRCCOPY); break; case 2: pDC->BitBlt(pt.x, pt.y, bm.bmWidth / 3, bm.bmHeight,&MemDC, bm.bmWidth / 3, 0, SRCCOPY); break; case 3: pDC->BitBlt(pt.x, pt.y, bm.bmWidth / 3, bm.bmHeight,&MemDC, bm.bmWidth * 2 / 3, 0, SRCCOPY); break; } m_bmRt.left = pt.x;//m_bmRt为全局. m_bmRt.top = pt.y; m_bmRt.right = pt.x + bm.bmWidth / 3; m_bmRt.bottom = pt.y + bm.bmHeight; MemDC.SelectObject (pOldBitmap); ReleaseDC(&MemDC); cbmp.DeleteObject(); pOldBitmap->DeleteObject(); return true; } ////////////Bitmap Load Function end/////////////////////// ////////////Draw NC//////////////////////////////////////// void CMYSkinDlg::DrawNC(CDC* pDC) { if (m_hWnd) { CRect rtTitle;// //整个Window的相对于屏幕的矩形 GetWindowRect(&m_rtWnd); //取得整个Title bar的矩形 rtTitle.left=0; rtTitle.top=0; rtTitle.right=m_rtWnd.Width()+3; rtTitle.bottom=rtTitle.top+m_nCaptionHeight + 4; //重画Title Bar if (m_bNCActive) { FillWithBmpRtUL("UL",pDC,CPoint(0,0)); CRect rtUL=m_bmRt; FillWithBmpRtUR("C2",pDC,CPoint(rtTitle.right-3,rtTitle.top)); FillRtWithBmp("C1",pDC,CRect(rtTitle.left+rtUL.Width(),rtTitle.top,rtTitle.right-m_bmRt.Width()-3,rtTitle.bottom)); } else { FillWithBmpRtUL("UL_N",pDC,CPoint(0,0)); CRect rtUL=m_bmRt; FillWithBmpRtUR("C2_N",pDC,CPoint(rtTitle.right-3,rtTitle.top)); FillRtWithBmp("C1_N",pDC,CRect(rtTitle.left+rtUL.Width(),rtTitle.top,rtTitle.right-m_bmRt.Width()-3,rtTitle.bottom)); } //重画icon HICON hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_rtIcon.left=rtTitle.left+15; m_rtIcon.top=rtTitle.top+2; m_rtIcon.right=m_rtIcon.left+rtTitle.Height()-5; m_rtIcon.bottom=m_rtIcon.top+rtTitle.Height()-5; ::DrawIconEx(pDC->m_hDC, m_rtIcon.left, m_rtIcon.top, hIcon, m_rtIcon.Height(), m_rtIcon.Width(), 0, NULL,DI_NORMAL); m_rtIcon.OffsetRect(m_rtWnd.TopLeft()); //记录Icon屏幕位置 //重画最大最小关闭button //MIN FillButton("BTN_MIN",pDC,CPoint(m_rtWnd.Width()-80,8),1); m_rtButtMin=m_bmRt; m_rtButtMinM=m_rtButtMin;//记录最小button屏幕位置 m_rtButtMin.OffsetRect(m_rtWnd.TopLeft()); //记录最小button屏幕位置 //NOM/MAX if(IsZoomed()) FillButton("BTN_NOM",pDC,CPoint(m_bmRt.right,8),1); else FillButton("BTN_MAX",pDC,CPoint(m_bmRt.right,8),1); m_rtButtMax=m_bmRt; m_rtButtMaxM=m_rtButtMax;//记录button屏幕位置 m_rtButtMax.OffsetRect(m_rtWnd.TopLeft());//记录button屏幕位置 //CLS FillButton("BTN_CLS",pDC,CPoint(m_bmRt.right,8),1); m_rtButtExit=m_bmRt; m_rtButtExitM=m_rtButtExit;//记录关闭button屏幕位置 m_rtButtExit.OffsetRect(m_rtWnd.TopLeft());//记录关闭button屏幕位置 //重画caption int nOldtMode=pDC->SetBkMode(TRANSPARENT); COLORREF clOldText = pDC->SetTextColor(RGB(150, 150, 150)); pDC->SelectStockObject(DEVICE_DEFAULT_FONT); CSize sz=pDC->GetTextExtent(m_strCaption); rtTitle.right-=GetSystemMetrics(SM_CYSMICON); rtTitle.top=6; //Caption阴影. pDC->DrawText(_T(m_strCaption), -1, &CRect(rtTitle.left+1,rtTitle.top+1,rtTitle.right+1,rtTitle.bottom+1), DT_CENTER); if(m_bNCActive) clOldText=pDC->SetTextColor(RGB(255, 255, 255)); else clOldText=pDC->SetTextColor(RGB(100, 100, 100)); pDC->DrawText(_T(m_strCaption), -1, &rtTitle, DT_CENTER); pDC->SetBkMode(nOldtMode); pDC->SetTextColor(clOldText); //重画左边框 CRect rtborder; rtborder.left=0; rtborder.top=rtTitle.bottom; rtborder.right=rtborder.left+4; rtborder.bottom=rtborder.top+m_rtWnd.Height(); if (m_bNCActive) { FillRtWithBmp("L",pDC,rtborder); } else { FillRtWithBmp("L_N",pDC,rtborder); } //重画右边框 rtborder.left=m_rtWnd.Width()-4; //rtborder.top同左边框. rtborder.right=rtborder.left+4; rtborder.bottom=rtborder.top+m_rtWnd.Height(); if (m_bNCActive) { FillRtWithBmp("R",pDC,rtborder); } else { FillRtWithBmp("R_N",pDC,rtborder); } //重画下边框 rtborder.left=0; rtborder.top=m_rtWnd.Height()-4; rtborder.right=rtborder.Width(); rtborder.bottom=rtborder.top+4; if(m_bNCActive) { FillRtWithBmp("BC1",pDC,rtborder); FillWithBmpRtUR("BC2",pDC,CPoint(rtborder.right-4,rtborder.top)); FillWithBmpRtUL("BL",pDC,CPoint(rtborder.left,rtborder.top)); FillWithBmpRtUL("BR",pDC,CPoint(rtborder.right-4,rtborder.top)); } else { FillRtWithBmp("BC1_N",pDC,rtborder); FillWithBmpRtUL("BL_N",pDC,CPoint(rtborder.left,rtborder.top)); FillWithBmpRtUL("BR_N",pDC,CPoint(rtborder.right-4,rtborder.top)); } } } ////////////Draw NC end//////////////////////////////////////// int CMYSkinDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { this->ModifyStyle(WS_SYSMENU, 0);//防止在任务栏右单击时出现最大最小关闭. GetWindowText(m_strCaption);//为自绘的标题做准备. if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; return 0; } void CMYSkinDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { //CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); if (bSysMenu) OnNcPaint();//防止在任务栏右键图标时窗口出现最大最小关闭 } void CMYSkinDlg::OnNcMouseMove(UINT nHitTest, CPoint point) { //检测最小,最大和关闭按钮是否有鼠标悬停,然后更换. if (m_rtButtExit.PtInRect(point)) { CDC* pWinDC=GetWindowDC();//绘关闭按钮悬停时的图标 FillButton("BTN_CLS",pWinDC,CPoint(m_rtButtExitM.left,m_rtButtExitM.top),2); FillButton("BTN_MIN",pWinDC,CPoint(m_rtButtMinM.left,m_rtButtMinM.top),1); if (IsZoomed()) FillButton("BTN_NOM",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); else FillButton("BTN_MAX",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); ReleaseDC(pWinDC); } else if (m_rtButtMin.PtInRect(point)) { //绘最小化按钮悬停时的图标 CDC* pWinDC=GetWindowDC(); FillButton("BTN_CLS",pWinDC,CPoint(m_rtButtExitM.left,m_rtButtExitM.top),1); FillButton("BTN_MIN",pWinDC,CPoint(m_rtButtMinM.left,m_rtButtMinM.top),2); if (IsZoomed()) FillButton("BTN_NOM",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); else FillButton("BTN_MAX",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); ReleaseDC(pWinDC); } else if (m_rtButtMax.PtInRect(point)) { //绘最大化按钮悬停时的图标 CDC* pWinDC=GetWindowDC(); FillButton("BTN_CLS",pWinDC,CPoint(m_rtButtExitM.left,m_rtButtExitM.top),1); FillButton("BTN_MIN",pWinDC,CPoint(m_rtButtMinM.left,m_rtButtMinM.top),1); if (IsZoomed()) FillButton("BTN_NOM",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),2); else FillButton("BTN_MAX",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),2); ReleaseDC(pWinDC); } else { CDC* pWinDC=GetWindowDC(); FillButton("BTN_CLS",pWinDC,CPoint(m_rtButtExitM.left,m_rtButtExitM.top),1); FillButton("BTN_MIN",pWinDC,CPoint(m_rtButtMinM.left,m_rtButtMinM.top),1); if (IsZoomed()) FillButton("BTN_NOM",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); else FillButton("BTN_MAX",pWinDC,CPoint(m_rtButtMaxM.left,m_rtButtMaxM.top),1); ReleaseDC(pWinDC); } } LRESULT CMYSkinDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_NCHITTEST) { LRESULT lRet = CDialog::WindowProc(message, wParam, lParam); if (lRet==HTZOOM || lRet == HTMINBUTTON || lRet == HTCLOSE)//屏蔽最大最小关闭消息. //.net03:ms-help:wm_nchittest return HTCAPTION; else return lRet; } // 在OnNcActivate 和OnInitMenuPopup 中也处理最大和最小关闭误显示的问题. else if (message == WM_SETCURSOR || message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONUP || message == WM_NCLBUTTONDBLCLK|| message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONDBLCLK || message == 0x0125 /*WM_UNINITMENUPOPUP*/) { ModifyStyle(WS_SYSMENU, 0);//移除系统菜单. LRESULT lRet = CDialog::WindowProc(message, wParam, lParam); //ModifyStyle(0, WS_SYSMENU); return lRet; } return CDialog::WindowProc(message, wParam, lParam); } HBRUSH CMYSkinDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { if (nCtlColor == CTLCOLOR_DLG) return m_brBG;//对话框背景颜色. return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); } void CMYSkinDlg::PreSubclassWindow() { // TODO: 在此添加专用代码和/或调用基类 //得到标题栏图片高度。 CString bmpFileName="C2"; HBITMAP bitmap; bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(), "skin//"+_T(bmpFileName)+".bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE); BITMAP bm; CBitmap cbmp; cbmp.Attach(bitmap); cbmp.GetBitmap(&bm); cbmp.DeleteObject(); m_nCaptionHeight=bm.bmHeight-4; CDialog::PreSubclassWindow(); } 4.改进 不足之处: (1)只针对对话框。 (2)图片重绘时的闪烁问题。 (3)图片装载时的错误处理。 (4)最大最小关闭图标依然显示的问题。 (5)border宽度不能随窗口样式改变的问题。 (6)没有解决最大最小的不使能,显/隐的问题。 (7)XP环境下的最佳性能时标题栏左上和右上角多余区域的处理。 (8)程序有待进一步简化和优化。
相关文章推荐
- VC 实现 自绘 窗体 标题栏 非客户区
- VC MFC 钩子 实现 自绘 窗体 标题栏 非客户区
- 界面编程:VC实现自绘窗体标题栏非客户区
- VC 实现 自绘 窗体 标题栏 非客户区
- VC 实现 自绘 窗体 标题栏 非客户区
- 【转】 VC MFC 钩子 实现 自绘 窗体 标题栏 非客户区
- VC MFC 钩子 实现 自绘 窗体 标题栏 非客户区(VER.2013-11-06)
- VC 实现 自绘 窗体 标题栏 非客户区
- VC 实现 自绘 窗体 标题栏 非客户区
- VC 实现自绘 窗体 标题栏 非客户区
- MFC对话框禁止移动 使标题栏不响应鼠标消息 通过客户区移动窗体 OnNcHitTest()的实现
- MFC对话框禁止移动 使标题栏不响应鼠标消息 通过客户区移动窗体 OnNcHitTest()的实现
- vc++如何将客户区存为bmp和VC实现自绘图形输出到bmp文件
- MFC 客户区 模拟标题栏 功能 ,实现窗体拖动
- VC环境中获取窗体标题栏的位置和高度
- VC++ WIN32 sdk实现按钮自绘详解.
- VC++调用UpdateLayeredWindow实现半透明窗体【转】
- 用VC++实现自绘按钮控制
- 修改窗体非客户区大小更改窗体标题栏高度
- VC实现自绘图形输出到bmp文件