从CButton派生出来一个类,然后给复选按钮添加了新CButton类的控件变量后,然后SetCheck、GetCheck就全都失效了,这是什么情况啊?哪些操作可能会导致这种结果啊?
class CGdiPlusBitmapResource;
/////////////////////////////////////////////////////////////////////////////
// CGdipButton window
class CGdipButton : public CButton
{
public:
CGdipButton();
virtual ~CGdipButton();
// image types
enum {
STD_TYPE = 0,
ALT_TYPE,
DIS_TYPE
};
// sets the image type
void SetImage(int type);
BOOL LoadAltImage(UINT id, LPCTSTR pType);
BOOL LoadStdImage(UINT id, LPCTSTR pType);
// if false, disables the press state and uses grayscale image if it exists
void EnableButton(BOOL bEnable = TRUE) { m_bIsDisabled = !bEnable; }
// 启用切换模式,在切换模式下,每按切换之间的STD和Alt图像
void EnableToggle(BOOL bEnable = TRUE);
void InitToggle(BOOL bEnable);//切换图像
// return the enable/disable state
BOOL IsDisabled(void) {return (m_bIsDisabled == TRUE); }
void SetBkGnd(CDC* pDC);
void SetToolTipText(CString spText, BOOL bActivate = TRUE);
void SetToolTipText(UINT nId, BOOL bActivate = TRUE);
void SetHorizontal(bool ImagesAreLaidOutHorizontally = FALSE);
void DeleteToolTip();
protected:
void PaintBk(CDC* pDC);
void PaintBtn(CDC* pDC);
BOOL m_bHaveAltImage;
BOOL m_bHaveBitmaps;
BOOL m_bIsDisabled;
BOOL m_bIsToggle;
BOOL m_bIsHovering;
BOOL m_bIsTracking;
int m_nCurType;
CGdiPlusBitmapResource* m_pAltImage;
CGdiPlusBitmapResource* m_pStdImage;
CString m_tooltext;
CToolTipCtrl* m_pToolTip;
void InitToolTip();
virtual void PreSubclassWindow();
virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
virtual BOOL PreTranslateMessage(MSG* pMsg);
//{{AFX_MSG(CGdipButton)
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam) ;
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CDC m_dcBk; // button background
CDC m_dcStd; // standard button
CDC m_dcStdP; // standard button pressed
CDC m_dcStdH; // standard button hot
CDC m_dcAlt; // alternate button
CDC m_dcAltP; // alternate button pressed
CDC m_dcAltH; // alternate button hot
CDC m_dcGS; // grayscale button (does not have a hot or pressed state)
CDC* m_pCurBtn; // current pointer to one of the above
};
#include "pch.h"
#include "GdipButton.h"
#include "CGdiPlusBitmap.h"
#include "MemDC.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGdipButton
CGdipButton::CGdipButton()
{
m_pStdImage = NULL;
m_pAltImage = NULL;
m_bHaveBitmaps = FALSE;
m_bHaveAltImage = FALSE;
m_pCurBtn = NULL;
m_bIsDisabled = FALSE;
m_bIsToggle = FALSE;
m_bIsHovering = FALSE;
m_bIsTracking = FALSE;
m_nCurType = STD_TYPE;
m_pToolTip = NULL;
}
CGdipButton::~CGdipButton()
{
if(m_pStdImage) delete m_pStdImage;
if(m_pAltImage) delete m_pAltImage;
if(m_pToolTip) delete m_pToolTip;
}
BEGIN_MESSAGE_MAP(CGdipButton, CButton)
//{{AFX_MSG_MAP(CGdipButton)
ON_WM_DRAWITEM()
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR_REFLECT()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//=============================================================================
//
// LoadStdImage()
//
// Purpose: The LoadStdImage() Loads the image for the button. This
// function must be called at a minimum or the button wont do
// anything.
//
// Parameters:
// [IN] id
// resource id, one of the resources already imported with the
// resource editor, usually begins with IDR_
//
// [IN] pType
// pointer to string describing the resource type
//
// Returns: BOOL
// Non zero if successful, otherwise zero
//
//=============================================================================
BOOL CGdipButton::LoadStdImage(UINT id, LPCTSTR pType)
{
m_pStdImage = new CGdiPlusBitmapResource;
return m_pStdImage->Load(id, pType);
}
//=============================================================================
//
// LoadAltImage()
//
// Purpose: The LoadAltImage() Loads the altername image for the button.
// This function call is optional
// Parameters:
// [IN] id
// resource id, one of the resources already imported with the
// resource editor, usually begins with IDR_
//
// [IN] pType
// pointer to string describing the resource type
//
// Returns: BOOL
// Non zero if successful, otherwise zero
//
//=============================================================================
BOOL CGdipButton::LoadAltImage(UINT id, LPCTSTR pType)
{
m_bHaveAltImage = TRUE;
m_pAltImage = new CGdiPlusBitmapResource;
return (m_pAltImage->Load(id, pType));
}
//=============================================================================
//
// The framework calls this member function when a child control is about to
// be drawn. All the bitmaps are created here on the first call. Every thing
// is done with a memory DC except the background, which get's it's information
// from the parent. The background is needed for transparent portions of PNG
// images. An always on top app (such as Task Manager) that is in the way can
// cause it to get an incorrect background. To avoid this, the parent should
// call the SetBkGnd function with a memory DC when it creates the background.
//
//=============================================================================
HBRUSH CGdipButton::CtlColor(CDC* pScreenDC, UINT nCtlColor)
{
if(!m_bHaveBitmaps)
{
if(!m_pStdImage)
{
return NULL; // Load the standard image with LoadStdImage()
}
CBitmap bmp, *pOldBitmap;
CRect rect;
GetClientRect(rect);
// do everything with mem dc
CGdiMemDC pDC(pScreenDC, rect);
Gdiplus::Graphics graphics(pDC->m_hDC);
// 背景
if (m_dcBk.m_hDC == NULL)
{
CRect rect1;
CClientDC clDC(GetParent());
GetWindowRect(rect1);
GetParent()->ScreenToClient(rect1);
m_dcBk.CreateCompatibleDC(&clDC);
bmp.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
bmp.DeleteObject();
}
// 标准图像
if (m_dcStd.m_hDC == NULL)
{
PaintBk(pDC);
//////////////////////////////////////////////////////////////////////
//graphics.DrawImage(*m_pStdImage, 0, 0);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X = 0, grect.Y = 0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pStdImage, grect, 0, 0, width, height, UnitPixel);
///////////////////////////////////////////////////////////////////////////
m_dcStd.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStd.SelectObject(&bmp);
m_dcStd.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
// 按钮点击状态
if (m_dcStdP.m_hDC == NULL)
{
PaintBk(pDC);
///////////////////////////////////////////////////////////////////////////
//graphics.DrawImage(*m_pStdImage, 1, 1);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X = 0, grect.Y = 0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pStdImage, grect, -1, -1, width, height, UnitPixel);
///////////////////////////////////////////////////////////////////////////
m_dcStdP.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStdP.SelectObject(&bmp);
m_dcStdP.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
// 按钮悬停状态
if(m_dcStdH.m_hDC == NULL)
{
PaintBk(pDC);
ColorMatrix HotMat = { 1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.05f, 0.05f, 0.05f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&HotMat);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pStdImage, grect, 0, 0, width, height, UnitPixel, &ia);
m_dcStdH.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcStdH.SelectObject(&bmp);
m_dcStdH.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
// grayscale image
if(m_dcGS.m_hDC == NULL)
{
PaintBk(pDC);
ColorMatrix GrayMat = { 0.30f, 0.30f, 0.30f, 0.00f, 0.00f,
0.59f, 0.59f, 0.59f, 0.00f, 0.00f,
0.11f, 0.11f, 0.11f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.00f, 0.00f, 0.00f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&GrayMat);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pStdImage, grect, 0, 0, width, height, UnitPixel, &ia);
m_dcGS.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcGS.SelectObject(&bmp);
m_dcGS.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
}
// alternate image
if( (m_dcAlt.m_hDC == NULL) && m_bHaveAltImage )
{
PaintBk(pDC);
//graphics.DrawImage(*m_pAltImage, 0, 0);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X = 0, grect.Y = 0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pAltImage, grect, 0, 0, width, height, UnitPixel);
m_dcAlt.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcAlt.SelectObject(&bmp);
m_dcAlt.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
// alternate image pressed
if( (m_dcAltP.m_hDC == NULL) && m_bHaveAltImage )
{
PaintBk(pDC);
//graphics.DrawImage(*m_pAltImage, 1, 1);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X = 0, grect.Y = 0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pAltImage, grect, 0, 0, width, height, UnitPixel);
m_dcAltP.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcAltP.SelectObject(&bmp);
m_dcAltP.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
// alternate image hot
if(m_dcAltH.m_hDC == NULL)
{
PaintBk(pDC);
ColorMatrix HotMat = { 1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.05f, 0.05f, 0.05f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&HotMat);
float width = (float)m_pStdImage->m_pBitmap->GetWidth();
float height = (float)m_pStdImage->m_pBitmap->GetHeight();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
graphics.DrawImage(*m_pAltImage, grect, 0, 0, width, height, UnitPixel, &ia);
m_dcAltH.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcAltH.SelectObject(&bmp);
m_dcAltH.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
bmp.DeleteObject();
}
}
if(m_pCurBtn == NULL)
{
m_pCurBtn = &m_dcStd;
}
m_bHaveBitmaps = TRUE;
}
return NULL;
}
//=============================================================================
// 画背景
//=============================================================================
void CGdipButton::PaintBk(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
}
//=============================================================================
// 使用m_pCurBtn绘制当前指向的位图
//=============================================================================
void CGdipButton::PaintBtn(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), m_pCurBtn, 0, 0, SRCCOPY);
}
//=============================================================================
// 启用切换模式
// 如果没有备用图像则返回
//=============================================================================
void CGdipButton::EnableToggle(BOOL bEnable)
{
if(!m_bHaveAltImage) return;
m_bIsToggle = bEnable;
// this actually makes it start in the std state since toggle is called before paint
if(bEnable) m_pCurBtn = &m_dcAlt;
else m_pCurBtn = &m_dcStd;
}
void CGdipButton::InitToggle(BOOL bEnable)
{
m_nCurType = bEnable;
Invalidate();
}
//=============================================================================
// 设置图像类型和禁用状态,然后重新绘制
//=============================================================================
void CGdipButton::SetImage(int type)
{
m_nCurType = type;
(type == DIS_TYPE) ? m_bIsDisabled = TRUE : m_bIsDisabled = FALSE;
Invalidate();
}
//=============================================================================
// 将控件设置为所有者绘制
//=============================================================================
void CGdipButton::PreSubclassWindow()
{
// 将控件设置为所有者绘制
ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED);
CButton::PreSubclassWindow();
}
//=============================================================================
// 禁用双击
//=============================================================================
BOOL CGdipButton::PreTranslateMessage(MSG* pMsg)
{
/*if (pMsg->message == WM_LBUTTONDBLCLK)
pMsg->message = WM_LBUTTONDOWN;
if (m_pToolTip != NULL)
{
if (::IsWindow(m_pToolTip->m_hWnd))
{
m_pToolTip->RelayEvent(pMsg);
}
}*/
return CButton::PreTranslateMessage(pMsg);
}
//=============================================================================
// 覆盖erase函数
//=============================================================================
BOOL CGdipButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
//=============================================================================
// 根据鼠标的状态绘制按钮
//=============================================================================
void CGdipButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CString sCaption;
//CDC* pDC = CDC::FromHandle(lpDIS->hDC); // get device context
RECT r = lpDIS->rcItem; // context rectangle
int cx = r.right - r.left; // get width
int cy = r.bottom - r.top; // get height
RECT tr = { r.left + 0 + 2,r.top,r.right - 0 - 2,r.bottom };
// 处理禁用状态
if(m_bIsDisabled)
{
m_pCurBtn = &m_dcGS;
PaintBtn(pDC);
GetWindowText(sCaption); // 获得按钮文本
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT));
pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}
BOOL bIsPressed = (lpDIS->itemState & ODS_SELECTED);
// 手柄开关按钮
if(m_bIsToggle && bIsPressed)
{
(m_nCurType == STD_TYPE) ? m_nCurType = ALT_TYPE : m_nCurType = STD_TYPE;
}
if(bIsPressed)//按下状态
{
if(m_nCurType == STD_TYPE)
m_pCurBtn = &m_dcStdP;
else
m_pCurBtn = &m_dcAltP;
}
else if(m_bIsHovering)//悬停状态
{
if(m_nCurType == STD_TYPE)
m_pCurBtn = &m_dcStdH;
else
m_pCurBtn = &m_dcAltH;
}
else//初始状态
{
if(m_nCurType == STD_TYPE)
m_pCurBtn = &m_dcStd;
else
m_pCurBtn = &m_dcAlt;
}
// 画按钮
PaintBtn(pDC);
GetWindowText(sCaption); // 获取按钮文本
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(/*(RGB(0x2f, 0x4f, 0x4f))*/GetSysColor(COLOR_3DHILIGHT));
pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
}
//=============================================================================
LRESULT CGdipButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
//=============================================================================
{
m_bIsHovering = TRUE;
Invalidate();
DeleteToolTip();
// 用新的按钮大小和位置创建一个新的工具提示
SetToolTipText(m_tooltext);
if (m_pToolTip != NULL)
{
if (::IsWindow(m_pToolTip->m_hWnd))
{
//显示工具提示
m_pToolTip->Update();
}
}
return 0;
}
//=============================================================================
LRESULT CGdipButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
//=============================================================================
{
m_bIsTracking = FALSE;
m_bIsHovering = FALSE;
Invalidate();
return 0;
}
//=============================================================================
void CGdipButton::OnMouseMove(UINT nFlags, CPoint point)
//=============================================================================
{
if (!m_bIsTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bIsTracking = _TrackMouseEvent(&tme);
}
CButton::OnMouseMove(nFlags, point);
}
//=============================================================================
//
// Call this member function with a memory DC from the code that paints
// the parents background. Passing the screen DC defeats the purpose of
// using this function.
//
//=============================================================================
void CGdipButton::SetBkGnd(CDC* pDC)
{
CRect rect, rectS;
CBitmap bmp, *pOldBitmap;
GetClientRect(rect);
GetWindowRect(rectS);
GetParent()->ScreenToClient(rectS);
m_dcBk.DeleteDC();
m_dcBk.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rectS.left, rectS.top, SRCCOPY);
bmp.DeleteObject();
}
//=============================================================================
// 使用字符串资源设置工具提示
//=============================================================================
void CGdipButton::SetToolTipText(UINT nId, BOOL bActivate)
{
// 加载字符串资源
m_tooltext.LoadString(nId);
// 如果字符串资源不为空
if (m_tooltext.IsEmpty() == FALSE)
{
SetToolTipText(m_tooltext, bActivate);
}
}
//=============================================================================
// 使用CString设置工具提示
//=============================================================================
void CGdipButton::SetToolTipText(CString spText, BOOL bActivate)
{
// 不能接受NULL指针
if (spText.IsEmpty()) return;
// 初始化提示
InitToolTip();
m_tooltext = spText;
// 如果没有定义工具提示,那么添加它
if (m_pToolTip->GetToolCount() == 0)
{
CRect rectBtn;
GetClientRect(rectBtn);
m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);
}
// 设置工具提示的文本
m_pToolTip->UpdateTipText(m_tooltext, this, 1);
m_pToolTip->SetDelayTime(2000);
m_pToolTip->Activate(bActivate);
}
//=============================================================================
void CGdipButton::InitToolTip()
//=============================================================================
{
if (m_pToolTip == NULL)
{
m_pToolTip = new CToolTipCtrl;
// 创建工具提示控件
m_pToolTip->Create(this);
m_pToolTip->Activate(TRUE);
}
}
//=============================================================================
void CGdipButton::DeleteToolTip()
//=============================================================================
{
// 破坏工具提示,以防按钮的大小改变。
if (m_pToolTip != NULL)
{
delete m_pToolTip;
m_pToolTip = NULL;
}
}