Code
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 实现 自绘 窗体 标题栏 非客户区
本程序在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)程序有待进一步简化和优化。