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);
}