您的位置:首页 > 其它

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)程序有待进一步简化和优化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: