📄 skinbutton.cpp
字号:
#include "stdafx.h"
#include "SkinButton.h"
#include "Resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
LRESULT CALLBACK SkinButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC OldWndProc=NULL;
CSkinButton *pSkinButton=NULL;
// 首先获取以前保存的原始的WndProc的地址。
OldWndProc=(WNDPROC)GetProp(hwnd,"OldWndProc");
ASSERT(OldWndProc != NULL);
// 然后是这个控件的SkinButton对象。
pSkinButton=(CSkinButton*)GetProp(hwnd,"SkinButtonObj");
ASSERT(pSkinButton != NULL);
// 然后开始处理消息。
if (uMsg == WM_DRAWITEM)
{
pSkinButton->DrawItem((LPDRAWITEMSTRUCT)lParam);
return TRUE;
}
else if (uMsg == WM_ERASEBKGND)
{
// NOTE: 处理这些消息的时候,必须特别注意hDC的选用,如果参数中传递了HDC,
// 那么就必须用参数中的。不能再使用GetDC返回的。否则就会出现绘画错误的现象。
TRACE("SkinButton receive WM_ERASEBKGND message.\n");
CDC DC;
DC.Attach((HDC)wParam);
pSkinButton->OnEraseBkgnd(&DC);
DC.Detach(); // 不是我们创建的DC,我们不能销毁它。
return 1;
}
else if (uMsg == WM_PAINT)
{
TRACE("SkinButton receive WM_PAINT message.\n");
pSkinButton->OnPaint();
}
else if (uMsg == WM_DESTROY)
{
// 窗体注销,我们把我们所增加的Prop去掉。
RemoveProp(hwnd,"OldWndProc");
RemoveProp(hwnd,"SkinButtonObj");
// 还原以前的WNDPROC
SetWindowLong(hwnd,GWL_WNDPROC,(LONG)OldWndProc);
// 删除CSkinButton对象。
pSkinButton->m_hWnd=NULL;
delete pSkinButton;
return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
}
else if (uMsg == WM_MOUSEMOVE)
{
CPoint Point;
Point.x=GET_X_LPARAM(lParam);
Point.y=GET_Y_LPARAM(lParam);
pSkinButton->OnMouseMove((UINT)wParam,Point);
}
else if (uMsg == WM_MOUSEHOVER)
{
pSkinButton->OnMouseHover(wParam,lParam);
}
else if (uMsg == WM_MOUSELEAVE)
{
pSkinButton->OnMouseLeave(wParam,lParam);
}
return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
}
/////////////////////////////////////////////////////////////////////////////
// CSkinButton
CSkinButton::CSkinButton()
{
m_nXPos=10;
m_nYPos=6;
m_nNormalBitmapResID=IDB_BITMAP_NORMAL;
m_nFocusBitmapResID=IDB_BITMAP_FOCUS;
m_nHoverBitmapResID=0;
m_nPressedBitmapResID=IDB_BITMAP_DOWN;
m_bOverControl=FALSE;
m_bSelected=FALSE;
m_bTracking=FALSE;
m_bEnableStretch=TRUE;
//#ifndef SKIN_BUTTON_INIT_MACRO
//#error SKIN_BUTTON_INIT_MACRO not defined. CSkinButton can not work correctly without a SKIN_BUTTON_INIT_MACRO macro.
//#error see the document at the top of SkinButton.cpp for more information.
//#endif
// SKIN_BUTTON_INIT_MACRO
}
CSkinButton::~CSkinButton()
{
}
BEGIN_MESSAGE_MAP(CSkinButton, CButton)
//{{AFX_MSG_MAP(CSkinButton)
//ON_WM_ERASEBKGND() // 在通过MFC调用时,我们不用自己处理这两个消息,MFC
//ON_WM_PAINT() // 会给我们处理好的.如果多次一举,会造成死循环的.
//}}AFX_MSG_MAP
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSkinButton message handlers
void CSkinButton::DrawContent(CMemDC &pDC,UINT state,CRect rect,BOOL Focus,CString &strText)
{
CBitmap MyBitMap;
CDC MyBitmapDC;
MyBitmapDC.CreateCompatibleDC(NULL);
if (Focus)
{
if (state & ODS_SELECTED)
{
MyBitMap.LoadBitmap(m_nPressedBitmapResID);
}
else
{
MyBitMap.LoadBitmap(m_nFocusBitmapResID);
}
}
else if ((!m_bOverControl) || (m_nHoverBitmapResID == 0))
{
MyBitMap.LoadBitmap(m_nNormalBitmapResID);
}
else if (m_bOverControl)
{
MyBitMap.LoadBitmap(m_nHoverBitmapResID);
}
CBitmap* pOldBitmap=NULL;
VERIFY((pOldBitmap=MyBitmapDC.SelectObject(&MyBitMap)) != NULL);
// 这部分代码把图片进行切割后复制到目标区域。
CSize sizeBitMap;
BITMAP BitMapStruct={NULL};
MyBitMap.GetBitmap(&BitMapStruct);
sizeBitMap.cx=BitMapStruct.bmWidth;
sizeBitMap.cy=BitMapStruct.bmHeight;
// 下面是侧面条。
PAINTINFO PaintInfo[5]={NULL};
// 上边的侧边条
PaintInfo[0].sizeBlock.cx=sizeBitMap.cx-m_nXPos*2;
PaintInfo[0].sizeBlock.cy=m_nYPos;
PaintInfo[0].rectBlockSrc.left=m_nXPos;
PaintInfo[0].rectBlockSrc.top=0;
PaintInfo[0].rectBlockSrc.right=sizeBitMap.cx-m_nXPos;
PaintInfo[0].rectBlockSrc.bottom=m_nYPos;
PaintInfo[0].rectBlockDest.left=m_nXPos;
PaintInfo[0].rectBlockDest.top=0;
PaintInfo[0].rectBlockDest.right=rect.right-m_nXPos;
PaintInfo[0].rectBlockDest.bottom=m_nYPos;
// 下边的条
PaintInfo[1].sizeBlock.cx=sizeBitMap.cx-m_nXPos*2;
PaintInfo[1].sizeBlock.cy=m_nYPos;
PaintInfo[1].rectBlockSrc.left=m_nXPos;
PaintInfo[1].rectBlockSrc.top=sizeBitMap.cy-m_nYPos;
PaintInfo[1].rectBlockSrc.right=sizeBitMap.cx-m_nXPos;
PaintInfo[1].rectBlockSrc.bottom=sizeBitMap.cy;
PaintInfo[1].rectBlockDest.left=m_nXPos;
PaintInfo[1].rectBlockDest.top=rect.bottom-m_nYPos;
PaintInfo[1].rectBlockDest.right=rect.right-m_nXPos;
PaintInfo[1].rectBlockDest.bottom=rect.bottom;
// 左边的条
PaintInfo[2].sizeBlock.cx=m_nXPos;
PaintInfo[2].sizeBlock.cy=sizeBitMap.cy-m_nYPos*2;
PaintInfo[2].rectBlockSrc.left=0;
PaintInfo[2].rectBlockSrc.top=m_nYPos;
PaintInfo[2].rectBlockSrc.right=m_nXPos;
PaintInfo[2].rectBlockSrc.bottom=sizeBitMap.cy-m_nYPos;
PaintInfo[2].rectBlockDest.left=0;
PaintInfo[2].rectBlockDest.top=m_nYPos;
PaintInfo[2].rectBlockDest.right=m_nXPos;
PaintInfo[2].rectBlockDest.bottom=rect.bottom-m_nYPos;
// 右边的条
PaintInfo[3].sizeBlock.cx=m_nXPos;
PaintInfo[3].sizeBlock.cy=sizeBitMap.cy-m_nYPos*2;
PaintInfo[3].rectBlockSrc.left=sizeBitMap.cx-m_nXPos;
PaintInfo[3].rectBlockSrc.top=m_nYPos;
PaintInfo[3].rectBlockSrc.right=sizeBitMap.cx;
PaintInfo[3].rectBlockSrc.bottom=sizeBitMap.cy-m_nYPos;
PaintInfo[3].rectBlockDest.left=rect.right-m_nXPos;
PaintInfo[3].rectBlockDest.top=m_nYPos;
PaintInfo[3].rectBlockDest.right=rect.right;
PaintInfo[3].rectBlockDest.bottom=rect.bottom-m_nYPos;
// 中间的部分。
PaintInfo[4].sizeBlock.cx=sizeBitMap.cx-m_nXPos*2;
PaintInfo[4].sizeBlock.cy=sizeBitMap.cy-m_nYPos*2;
PaintInfo[4].rectBlockSrc.left=m_nXPos;
PaintInfo[4].rectBlockSrc.top=m_nYPos;
PaintInfo[4].rectBlockSrc.right=sizeBitMap.cx-m_nXPos;
PaintInfo[4].rectBlockSrc.bottom=sizeBitMap.cy-m_nYPos;
PaintInfo[4].rectBlockDest.left=m_nXPos;
PaintInfo[4].rectBlockDest.top=m_nYPos;
PaintInfo[4].rectBlockDest.right=rect.right-m_nXPos;
PaintInfo[4].rectBlockDest.bottom=rect.bottom-m_nYPos;
for (int i=0;i<5;i++)
{
PAINTINFO OnePaintInfo=PaintInfo[i];
if (!m_bEnableStretch)
{
if ((i == 0) || (i == 1))
{
int xPos=OnePaintInfo.rectBlockDest.left;
while (xPos <= OnePaintInfo.rectBlockDest.right)
{
pDC->BitBlt(xPos,OnePaintInfo.rectBlockDest.top,
OnePaintInfo.sizeBlock.cx,
OnePaintInfo.sizeBlock.cy,
&MyBitmapDC,OnePaintInfo.rectBlockSrc.left,OnePaintInfo.rectBlockSrc.top,
SRCCOPY);
xPos+=OnePaintInfo.sizeBlock.cx;
}
}
else if ((i == 2) || (i == 3))
{
int yPos=OnePaintInfo.rectBlockDest.top;
while (yPos <= OnePaintInfo.rectBlockDest.bottom)
{
pDC->BitBlt(OnePaintInfo.rectBlockDest.left,yPos,
OnePaintInfo.sizeBlock.cx,
OnePaintInfo.sizeBlock.cy,
&MyBitmapDC,OnePaintInfo.rectBlockSrc.left,OnePaintInfo.rectBlockSrc.top,
SRCCOPY);
yPos+=OnePaintInfo.sizeBlock.cy;
}
}
else
{
pDC->StretchBlt(OnePaintInfo.rectBlockDest.left,OnePaintInfo.rectBlockDest.top,
OnePaintInfo.rectBlockDest.right-OnePaintInfo.rectBlockDest.left,
OnePaintInfo.rectBlockDest.bottom-OnePaintInfo.rectBlockDest.top,
&MyBitmapDC,OnePaintInfo.rectBlockSrc.left,OnePaintInfo.rectBlockSrc.top,
OnePaintInfo.sizeBlock.cx,OnePaintInfo.sizeBlock.cy,
SRCCOPY);
}
}
else
{
pDC->StretchBlt(OnePaintInfo.rectBlockDest.left,OnePaintInfo.rectBlockDest.top,
OnePaintInfo.rectBlockDest.right-OnePaintInfo.rectBlockDest.left,
OnePaintInfo.rectBlockDest.bottom-OnePaintInfo.rectBlockDest.top,
&MyBitmapDC,OnePaintInfo.rectBlockSrc.left,OnePaintInfo.rectBlockSrc.top,
OnePaintInfo.sizeBlock.cx,OnePaintInfo.sizeBlock.cy,
SRCCOPY);
}
}
// 首先是左上角。
pDC->BitBlt(0,0,m_nXPos,m_nYPos,&MyBitmapDC,0,0,SRCCOPY);
// 然后是右上角
pDC->BitBlt(rect.right-m_nXPos,0,m_nXPos,m_nYPos,&MyBitmapDC,sizeBitMap.cx-m_nXPos,0,SRCCOPY);
// 左下角
pDC->BitBlt(0,rect.bottom-m_nYPos,m_nXPos,m_nYPos,&MyBitmapDC,0,sizeBitMap.cy-m_nYPos,SRCCOPY);
// 右下角
pDC->BitBlt(rect.right-m_nXPos,rect.bottom-m_nYPos,m_nXPos,m_nYPos,&MyBitmapDC,sizeBitMap.cx-m_nXPos,sizeBitMap.cy-m_nYPos,SRCCOPY);
MyBitmapDC.SelectObject(pOldBitmap);
// 显示标题
CFont Font;
Font.Attach((HFONT)::SendMessage(m_hWnd, WM_GETFONT, 0, 0));
CFont *oldFont=(CFont*)pDC->SelectObject(&Font);
if (strText != "")
{
CSize Extent = pDC->GetTextExtent(strText);
CPoint pt( rect.CenterPoint().x - Extent.cx/2,
rect.CenterPoint().y - Extent.cy/2 );
if (state & ODS_SELECTED)
{
pt.Offset(1,1);
}
int nMode = pDC->SetBkMode(TRANSPARENT);
if (state & ODS_DISABLED)
{
pDC->DrawState(pt, Extent, strText/*strCaption*/, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
}
else
{
pDC->DrawState(pt, Extent, strText/*strCaption*/, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);
}
pDC->SetBkMode(nMode);
}
pDC->SelectObject(oldFont);
Font.Detach();
}
void CSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT(m_nNormalBitmapResID != 0);
ASSERT(m_nFocusBitmapResID != 0);
ASSERT(m_nPressedBitmapResID != 0);
// TODO: Add your code to draw the specified item
CDC* ppDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CMemDC pDC(ppDC);
CRect rect = lpDrawItemStruct->rcItem;
UINT state = lpDrawItemStruct->itemState;
CString strText;
TCHAR szBuffer[1024]={NULL};
::GetWindowText(lpDrawItemStruct->hwndItem,szBuffer,1024);
strText=szBuffer;
if(state & ODS_FOCUS)
{
m_bFocus = TRUE;
m_bSelected = TRUE;
}
else
{
m_bSelected = FALSE;
m_bFocus = FALSE;
}
DrawContent(pDC,state,rect,m_bFocus,strText);
return;
}
void CSkinButton::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
ModifyStyle(0, BS_OWNERDRAW);
SetProp(m_hWnd,"SkinButtonHandled",(HANDLE)1);
CButton::PreSubclassWindow();
}
void CSkinButton::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bTracking = _TrackMouseEvent(&tme);
}
CButton::OnMouseMove(nFlags, point);
}
LRESULT CSkinButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
m_bOverControl=TRUE;
Invalidate();
return 1;
}
LRESULT CSkinButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
m_bTracking = FALSE;
m_bOverControl = FALSE;
Invalidate(FALSE);
return 0;
}
BOOL CSkinButton::SubClassWindow(HWND hWnd)
{
// 首先看看这个hWnd是不是以前已经被SubClass过了。
if (GetProp(hWnd,"SkinButtonObj") == NULL)
{
// 生成一个新的CSkinButton对象。
CSkinButton *pNewSkinButton=new CSkinButton;
pNewSkinButton->m_hWnd=hWnd; // 绕过Attach的检测。否则对于一个已经采用CButton控制的按钮会出现
// ASSERT警告的.
// 设置属性。
pNewSkinButton->m_bEnableStretch=m_bEnableStretch;
pNewSkinButton->m_nFocusBitmapResID=m_nFocusBitmapResID;
pNewSkinButton->m_nHoverBitmapResID=m_nHoverBitmapResID;
pNewSkinButton->m_nNormalBitmapResID=m_nNormalBitmapResID;
pNewSkinButton->m_nPressedBitmapResID=m_nPressedBitmapResID;
pNewSkinButton->m_nXPos=m_nXPos;
pNewSkinButton->m_nYPos=m_nYPos;
SetProp(hWnd,"SkinButtonObj",(HANDLE)pNewSkinButton);
// 然后是WNDPROC;
WNDPROC OldProc=(WNDPROC)GetWindowLong(hWnd,GWL_WNDPROC);
SetProp(hWnd,"OldWndProc",OldProc);
SetWindowLong(hWnd,GWL_WNDPROC,(LONG)SkinButtonSubclassProc);
return TRUE;
}
return FALSE;
}
BOOL CSkinButton::OnEraseBkgnd(CDC* pDC)
{
// 我们自己绘制按钮状态。
// 根据当前按钮的信息。
// TODO: Add your code to draw the specified item
CRect rect;
GetClientRect(rect);
CMemDC DC(pDC,&rect); // 由于传递近来的pDC不一定就是这个按钮的DC,
// 所以绘画的区域必须手动指定。
// pDC->GetClipBox != GetClientRect
UINT state = GetState();
CString strText;
TCHAR szBuffer[1024]={NULL};
::GetWindowText(m_hWnd,szBuffer,1024);
strText=szBuffer;
DrawContent(DC,state,rect,m_bFocus,strText);
return TRUE;//CButton::OnEraseBkgnd(pDC);
}
void CSkinButton::OnPaint()
{
CDC *pDc=GetDC(); // device context for painting
CRect rect;
GetClientRect(rect);
CMemDC DC(pDc,&rect);
UINT state = GetState();
CString strText;
TCHAR szBuffer[1024]={NULL};
::GetWindowText(m_hWnd,szBuffer,1024);
strText=szBuffer;
DrawContent(DC,state,rect,m_bFocus,strText);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -