记录一个MFC继承自CStatic的绘图bug

MFC想要动态加载图片并不是一件容易的 事情,在主窗口中重绘图形也很不划算,所以一般采用继承控件,自定义绘画的方式,定义一个结构体,结构体中存放HQ_Image picture;发现gdiplus中的drawImage返回11,即ValueOverflow。不知道什么原因,但是结构体改为HQ_Image* picture;就没问题。

HQ_Image*需要new ;采用的默认构造函数,HQ_Image不需要new,理论上是直接用默认构造函数初始化了的。但是不知道为什么会导致gdiplus drawimage返回失败

头文件

#pragma once
#include <afxwin.h>
#include <atlimage.h>
#include <gdiplus.h>

using namespace Gdiplus;

void CreateStretchImage(CImage *pImage, CImage *ResultImage, int StretchHeight, int StretchWidth);

class HQ_Image : public CStatic
{
	DECLARE_DYNAMIC(HQ_Image)
public:
	int m_nFontsize;
	void SetText(CString text);
	void SetTextColor(COLORREF TextColor);
	void SetBkColor(COLORREF bkColor);
	void UnsetBkColor();
	void Update();
	void SetBkImg(const TCHAR* ptszPath, int status = 0);
	void turnOn();
	void turnOff();
	void setHoverStatus(BOOL bHoveStatus = TRUE);
	int getStatus();
	void setImagePadding(int iPadding);

public:
	HQ_Image();
	virtual ~HQ_Image();

protected:
	DECLARE_MESSAGE_MAP()

private:
	afx_msg void OnPaint();
	LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	void Invalidate();

private:
	BOOL m_bTracking;
	BOOL m_bHoverSatus;
	CString m_text;
	int     m_padding;

	int m_status;//0:正常情况; 1:开启状态,用来切换图片

	// status 0
	COLORREF m_TextColor;
	BOOL m_bSetBkColor;
	COLORREF m_bkColor;
	Bitmap *m_pBkBitmap;
	CString m_strBitmap1;

	// status 1
	Bitmap *m_pBkBitmap_2;
	CString m_strBitmap2;
};

源文件

#include "HQ_Image.h"
#include "commonLog.h"//日志文件
using namespace ATL;

void CreateStretchImage(CImage *pImage, CImage *ResultImage, int StretchHeight, int StretchWidth)
{
	if (pImage->IsDIBSection())
	{
		// 取得 pImage 的 DC
		CDC* pImageDC1 = CDC::FromHandle(pImage->GetDC()); // Image 因為有自己的 DC, 所以必須使用 FromHandle 取得對應的 DC



		CBitmap *bitmap1 = pImageDC1->GetCurrentBitmap();
		BITMAP bmpInfo;
		bitmap1->GetBitmap(&bmpInfo);


		// 建立新的 CImage
		ResultImage->Create(StretchWidth, StretchHeight, bmpInfo.bmBitsPixel);
		CDC* ResultImageDC = CDC::FromHandle(ResultImage->GetDC());

		// 當 Destination 比較小的時候, 會根據 Destination DC 上的 Stretch Blt mode 決定是否要保留被刪除點的資訊
		ResultImageDC->SetStretchBltMode(HALFTONE); // 使用最高品質的方式
		::SetBrushOrgEx(ResultImageDC->m_hDC, 0, 0, NULL); // 調整 Brush 的起點


		// 把 pImage 畫到 ResultImage 上面
		StretchBlt(*ResultImageDC, 0, 0, StretchWidth, StretchHeight, *pImageDC1, 0, 0, pImage->GetWidth(), pImage->GetHeight(), SRCCOPY);
		// pImage->Draw(*ResultImageDC,0,0,StretchWidth,StretchHeight,0,0,pImage->GetWidth(),pImage->GetHeight());


		pImage->ReleaseDC();
		ResultImage->ReleaseDC();
	}
}

IMPLEMENT_DYNAMIC(HQ_Image, CStatic)
HQ_Image::HQ_Image()
{
	//TRACE("HQ_Image::HQ_Image()\n");  
	m_bSetBkColor = FALSE;
	m_pBkBitmap = NULL;
	m_pBkBitmap_2 = NULL;

	m_bTracking = FALSE;
	m_bHoverSatus = FALSE;
}

HQ_Image::~HQ_Image()
{
	if (NULL != m_pBkBitmap)
	{
		DeleteObject(m_pBkBitmap);
		m_pBkBitmap = NULL;
	}

	if (NULL != m_pBkBitmap_2)
	{
		DeleteObject(m_pBkBitmap_2);
		m_pBkBitmap_2 = NULL;
	}
	//TRACE("HQ_Image::~HQ_Image()\n");  
}


BEGIN_MESSAGE_MAP(HQ_Image, CStatic)
	ON_WM_PAINT()
END_MESSAGE_MAP()



// HQ_Image message handlers  

void HQ_Image::OnPaint()
{
	//TRACE("HQ_Image::OnPaint()\n");  
	CPaintDC dc(this); // device context for painting  

	// Where to draw text  
	CRect client_rect;
	GetClientRect(client_rect);

	//// Get the caption  
	//CString szText;
	//GetWindowText(szText);

	// Get the font  
	CFont *pFont, *pOldFont;
	pFont = GetFont();
	pOldFont = dc.SelectObject(pFont);


	// Map "Static Styles" to "Text Styles"  
#define MAP_STYLE(src, dest) if(dwStyle & (src)) dwText |= (dest)  
#define NMAP_STYLE(src, dest) if(!(dwStyle & (src))) dwText |= (dest)  

	DWORD dwStyle = GetStyle(), dwText = 0;

	MAP_STYLE(SS_RIGHT, DT_RIGHT);
	MAP_STYLE(SS_CENTER, DT_CENTER);
	MAP_STYLE(SS_CENTERIMAGE, DT_VCENTER | DT_SINGLELINE);
	MAP_STYLE(SS_NOPREFIX, DT_NOPREFIX);
	MAP_STYLE(SS_WORDELLIPSIS, DT_WORD_ELLIPSIS);
	MAP_STYLE(SS_ENDELLIPSIS, DT_END_ELLIPSIS);
	MAP_STYLE(SS_PATHELLIPSIS, DT_PATH_ELLIPSIS);

	NMAP_STYLE(SS_LEFTNOWORDWRAP |
		SS_CENTERIMAGE |
		SS_WORDELLIPSIS |
		SS_ENDELLIPSIS |
		SS_PATHELLIPSIS, DT_WORDBREAK);

	// Set transparent background
	dc.SetBkMode(TRANSPARENT);

	//解决重影(将对话框的背景图片贴到控件上)  
	CClientDC clDC(GetParent()); //创建其父窗口的客户区DC。由于此处控件的父窗口是对话框,因此就是获取对话框的DC。  
								 //相当于GetDC  
	CRect rect;
	CRect rect1;

	GetClientRect(rect);//获取本static控件的客户区大小  
	//this->GetClientRect(rect); //省去一个this,this就代表触发wm_paint消息的控件,以下同  
	GetWindowRect(rect1);//获取本static控件在窗口的位置和大小  
	GetParent()->ScreenToClient(rect1);//将本static控件的屏幕座标转换为客户区座标  
	
	if (m_bSetBkColor || NULL != m_pBkBitmap)
	{
		Graphics graphics(dc.GetSafeHdc());
		graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);

		Gdiplus::Rect rcDest(0, 0, rect.right, rect.bottom);

		if (m_bSetBkColor)
		{
			Gdiplus::SolidBrush brush(Color(255, GetRValue(m_bkColor), GetGValue(m_bkColor), GetBValue(m_bkColor)));
			graphics.FillRectangle(&brush, rcDest);
		}

		rcDest.X = m_padding;
		rcDest.Y = m_padding;
		rcDest.Width -= m_padding * 2;
		rcDest.Height -= m_padding * 2;

		if (1 == m_status && NULL != m_pBkBitmap_2)
		{
			graphics.DrawImage(m_pBkBitmap_2, rcDest, 0, 0,
				m_pBkBitmap->GetWidth(), m_pBkBitmap->GetHeight(), UnitPixel);
		}
		else
		{
			if (NULL != m_pBkBitmap)
			{
				graphics.DrawImage(m_pBkBitmap, rcDest, 0, 0,
					m_pBkBitmap->GetWidth(), m_pBkBitmap->GetHeight(), UnitPixel);
			}
		}

	}

	dc.SetTextColor(m_TextColor);//设置字体颜色  

	// Draw the text  
	dc.DrawText(m_text, client_rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);


	// Select old font  
	dc.SelectObject(pOldFont);
}

void HQ_Image::SetTextColor(COLORREF TextColor)
{
	//TRACE("HQ_Image::SetTextColor(COLORREF TextColor)\n");  
	m_TextColor = TextColor;
}

void HQ_Image::SetText(CString text)
{
	//TRACE("HQ_Image::SetTextColor(COLORREF TextColor)\n");  
	m_text = text;
}


//void HQ_Image::SetFont(int nSize)   
//{  
//  TRACE("HQ_Image::SetFont(int nSize)\n");  
//  m_nFontsize = nSize ;  
//  
//}  


void HQ_Image::SetBkColor(COLORREF bkColor)
{
	m_bSetBkColor = TRUE;
	m_bkColor = bkColor;

	Invalidate();
}

void HQ_Image::UnsetBkColor()
{
	m_bSetBkColor = FALSE;

	Invalidate();
}

void HQ_Image::Update()
{
	RECT rect;
	Status status;

	//大部分和onpaint中一样,暂不加入到onpaint中,以后可能为了兼容做其他处理
	if (m_bSetBkColor || NULL != m_pBkBitmap)
	{
		Invalidate();
		GetClientRect(&rect);//获取本static控件的客户区大小  

		CDC *pDC = GetDC();
		Graphics graphics(pDC->GetSafeHdc());
		graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);

		pDC->SetBkMode(TRANSPARENT);

		Gdiplus::Rect rcDest(0, 0, rect.right, rect.bottom);

		if (m_bSetBkColor)
		{
			Gdiplus::SolidBrush brush(Color(255, GetRValue(m_bkColor), GetGValue(m_bkColor), GetBValue(m_bkColor)));
			graphics.FillRectangle(&brush, rcDest);
		}

		rcDest.X = m_padding;
		rcDest.Y = m_padding;
		rcDest.Width -= m_padding * 2;
		rcDest.Height -= m_padding * 2;

		if (1 == m_status && NULL != m_pBkBitmap_2)
		{
			status = graphics.DrawImage(m_pBkBitmap_2, rcDest, 0, 0,
				m_pBkBitmap->GetWidth(), m_pBkBitmap->GetHeight(), UnitPixel);
		}
		else
		{
			if (NULL != m_pBkBitmap)
			{
				status = graphics.DrawImage(m_pBkBitmap, rcDest, 0, 0,
					m_pBkBitmap->GetWidth(), m_pBkBitmap->GetHeight(), UnitPixel);
			}
		}

		if (m_text.GetLength() > 0)
		{

			pDC->SetTextColor(m_TextColor);//设置字体颜色  

			// Draw the text  
			pDC->DrawText(m_text, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

		}


		//Invalidate();
		ReleaseDC(pDC);
	}
}

void HQ_Image::SetBkImg(const TCHAR* ptszPath, int status)
{
	if (0 == status)
	{
		if (NULL != m_pBkBitmap)
		{
			DeleteObject(m_pBkBitmap);
			m_pBkBitmap = NULL;
			//delete 会崩溃
			// delete m_pBkBitmap;
		}

		if (NULL == ptszPath || 0 == _tcslen(ptszPath))
		{
			m_pBkBitmap = NULL;

			Invalidate();

			return;
		}

		m_strBitmap1 = ptszPath;
		m_pBkBitmap = Bitmap::FromFile(ptszPath);
	}
	else
	{
		if (NULL != m_pBkBitmap_2)
		{
			DeleteObject(m_pBkBitmap_2);
			m_pBkBitmap_2 = NULL;
		}

		if (NULL == ptszPath || 0 == _tcslen(ptszPath))
		{
			m_pBkBitmap_2 = NULL;

			Invalidate();

			return;
		}

		m_strBitmap2 = ptszPath;
		m_pBkBitmap_2 = Bitmap::FromFile(ptszPath);
	}

	Update();
}

// 开启状态
void HQ_Image::turnOn()
{
	if (0 == m_status)
	{
		m_status = 1;
		Update();
	}
}

// 关闭状态,两种状态主要实现图片切换效果
void HQ_Image::turnOff()
{
	if (0 != m_status)
	{
		m_status = 0;
		Update();
	}
}

// 设置鼠标悬停事件与turn on一样
void HQ_Image::setHoverStatus(BOOL bHoveStatus)
{
	m_bHoverSatus = bHoveStatus;
}

int HQ_Image::getStatus()
{
	return m_status;
}

void HQ_Image::setImagePadding(int iPadding)
{
	if (iPadding < 1)
	{
		m_padding = 0;
		return;
	}

	CRect rect;

	GetClientRect(rect);//获取本static控件的客户区大小  

	if (iPadding >= rect.right / 2 || iPadding >= rect.bottom / 2)
	{
		return;
	}

	m_padding = iPadding;
}

void HQ_Image::Invalidate()
{
	RECT rect;

	POINT pt;

	GetWindowRect(&rect);
	pt.x = rect.left;
	pt.y = rect.top;
	::ScreenToClient(GetParent()->GetSafeHwnd(), &pt);

	GetClientRect(&rect);
	rect.left = pt.x;
	rect.top = pt.y;
	rect.right += rect.left;
	rect.bottom += rect.top;
	::InvalidateRect(GetParent()->GetSafeHwnd(), &rect, TRUE);
}

LRESULT HQ_Image::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_COMMAND:
		{
			break;
		}
		case WM_LBUTTONDOWN:
		{
			break;
		}
		case WM_MOUSEMOVE:
		{
			if (m_bHoverSatus && !m_bTracking)
			{
				TRACKMOUSEEVENT tme;
				tme.cbSize = sizeof(TRACKMOUSEEVENT);
				tme.dwFlags = TME_LEAVE | TME_HOVER;//要触发的消息
				tme.hwndTrack = GetSafeHwnd();
				tme.dwHoverTime = 10;// 若不设此参数,则无法触发mouseHover

				if (::_TrackMouseEvent(&tme)) //MOUSELEAVE|MOUSEHOVER消息由此函数触发
				{
					m_bTracking = true;
				}
			}
			break;
		}
		case WM_MOUSEHOVER:
		{
			if (m_bHoverSatus && !m_status)
			{
				turnOn();
			}

			m_bTracking = FALSE;
			break;
		}
		case WM_MOUSELEAVE:
		{
			if (m_bHoverSatus && m_status)
			{
				turnOff();
			}

			m_bTracking = FALSE;
			break;
		}
		default:
		{
			break;
		}
	}

	return CStatic::WindowProc(message, wParam, lParam);
}

猜你喜欢

转载自blog.csdn.net/youyudexiaowangzi/article/details/83894501