主要通过GDIPlus的Image类来加载图片资源,使之支持bmp以外的图片。
GDIPlus的初始化方式网上都是用的如下方法:
1、在stdafx.h中添加以下声明:
//引入GDI+头文件
#include <GdiPlus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib" )
2、在应用程序类初始化的地方(最好是InitInstance中)添加以下代码:
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
并在相应的头文件中声明:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
3、改写应用程序类的ExitInstance函数:
int CXXXApp::ExitInstance()
{
GdiplusShutdown(m_gdiplusToken);
return CWinApp::ExitInstance();
}
说明:VS2005及以上版本不需要添加GdiPlus.lib,否则手动添加
初始化的地方并不固定,下面是MSDN的例子:
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
INT main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Image* image = new Image(L"FakePhoto.jpg");
printf("The width of the image is %u.\n", image->GetWidth());
printf("The height of the image is %u.\n", image->GetHeight());
delete image;
GdiplusShutdown(gdiplusToken);
return 0;
}
该类继承与Cwnd类,首先是重载Create函数,获取图片资源,并建立窗口
下面是通过FromStream的方式获取资源,也可通过FromFile获取(详见另一种方法)
static bool ImageFromIDResource(UINT nID, LPCTSTR sTR,Image * &pImg)
{
bool ret = false;
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // sTR:type
if (!hRsrc)
return FALSE;
// load resource into memory
DWORD len = SizeofResource(hInst, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
//HGLOBAL lpRsrc = LoadResource(hInst, hRsrc);
if (!lpRsrc)
return FALSE;
LPVOID pBuffer = LockResource(lpRsrc);
if ( !pBuffer )
return false;
// Allocate global memory on which to create stream
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
//HGLOBAL m_hMem = GlobalAlloc(GMEM_ZEROINIT, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem,lpRsrc,len);
IStream* pstm;
if ( S_OK == CreateStreamOnHGlobal(m_hMem,FALSE,&pstm) )
{
// load from stream
pImg = Gdiplus::Image::FromStream(pstm);
if ( pImg )
ret = true;
}
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
FreeResource(lpRsrc);
//GlobalFree()
return ret;
}
然后建立该控件:
BOOL PNGButton::Create(UINT x,UINT y, CWnd* pParentWnd, UINT nID, \
UINT PngID,UINT PngID_hOver, UINT PngID_hDisable, UINT PngID_hClick, CCreateContext* pContext)
{
LPCTSTR lpszClassName=AfxRegisterWndClass( CS_HREDRAW|CS_VREDRAW , \
AfxGetApp()->LoadStandardCursor(IDC_ARROW), (HBRUSH)GetStockObject(TRANSPARENT), NULL);
ImageFromIDResource(PngID,_T("PNG"),this->m_bg);
ImageFromIDResource(PngID_hOver,L"PNG",this->m_hoverBg);
if ( 0 == PngID_hClick)
ImageFromIDResource(PngID,L"PNG", this->m_clickBg);
else
ImageFromIDResource(PngID_hClick,L"PNG", this->m_clickBg);
ImageFromIDResource(PngID_hDisable,L"PNG" ,this->m_DisableBg);
if ( !m_bg || !m_hoverBg || !m_clickBg ||!m_DisableBg)
{
return false;
}
m_Width=m_bg->GetWidth();
m_Height=m_bg->GetHeight();
BOOL OK=CWnd::Create(NULL,NULL,WS_CHILDWINDOW|WS_VISIBLE, CRect(x,y,x+m_Width,m_Height+y),pParentWnd, nID, pContext);
ModifyStyleEx(0, WS_EX_TRANSPARENT);// WS_EX_LAYERED||WS_EX_TRANSPARENT
//SetLayeredWindowAttributes(TRANSPARENT, (byte)(255 * 1), LWA_COLORKEY); //LWA_ALPHA LWA_COLORKEY
return OK;
}
然后只需重载Onpaint,根据不同的需要,画不同的图片即可
void PNGButton::OnPaint()
{
CPaintDC dc(this);
Graphics g(dc.m_hDC);
Bitmap bmp(this->m_Width,this->m_Height);
Graphics* gBuf=Graphics::FromImage(&bmp);
gBuf->DrawImage(this->m_bg,0,0);
//不同状态的显示
if ( !m_bIsEnable )
{
gBuf->DrawImage(m_DisableBg,0,0,0,0,m_Width,m_Height,Gdiplus::UnitPixel);
TRACE(L"m_bIsDisable\r\n");
}
else
{
if( m_bIsMouseHover )
{
gBuf->DrawImage(m_hoverBg,0,0,0,0,m_Width,m_Height,Gdiplus::UnitPixel);
TRACE(L"m_bIsMouseHover\r\n");
}
if ( m_bIsChecked )
{
gBuf->DrawImage(m_clickBg,0,0,0,0,m_Width,m_Height,Gdiplus::UnitPixel);
TRACE(L"m_bIsMouseClick\r\n");
}
}
delete gBuf;
g.DrawImage(&bmp,0,0);
g.ReleaseHDC(dc.m_hDC);
}
另一种方法继承自CButton类,因此可以不用动态创建,调用个方法加载图片资源就行,这里便是用FormFile来加载:
void CPngButton::SetButtonImage(CString str)
{
strImage = str;
m_pImage = Image::FromFile(str);
if ( !m_pImage )
{
return;
}
m_nWidth = m_pImage->GetWidth();
m_nHeight = m_pImage->GetHeight();
m_nSliceWidth = m_nWidth;
m_nSliceHeight = m_nHeight;
CWnd *pWnd = this -> GetParent();
GetWindowRect( &m_rectButton );
pWnd -> ScreenToClient(m_rectButton);
m_rectButton.right = m_rectButton.left + m_nSliceWidth;
m_rectButton.bottom = m_rectButton.top + m_nHeight;
//MoveWindow(m_rectButton); //调整按钮大小以适应图片
SetWindowPos(NULL,0,0,m_rectButton.Width(),m_rectButton.Height(),SWP_NOMOVE);
nWidth = m_rectButton.Width();
nHeight = m_rectButton.Height();
m_pGraphics = new Graphics(GetWindowDC()->m_hDC);
}
然后重载DrawItem,和第一个方法其实差不多:
CDC* pDC = CDC::FromHandle(lpDrawItemStruct -> hDC);
CRect rect = lpDrawItemStruct->rcItem;
UINT state = lpDrawItemStruct->itemState;
m_rcText = rect;
m_rcText.DeflateRect(1,1);
if(m_pGraphics == NULL)
return;
if(m_pImage == NULL)
return;
if( m_bDisable == TRUE )//RECT里面的参数是图片在控件中的大小、位置
{ //外面的参数是指定取图的范围、位置
m_pGraphics->DrawImage(m_pImage,Rect(0,0,m_nWidth,m_nSliceHeight),0,
0,m_nWidth, m_nSliceHeight,UnitPixel);
}
else
{
// click state
if( lpDrawItemStruct -> itemState & ODS_SELECTED )//m_pImage根据需要修改
{
m_pGraphics->DrawImage(m_pImage,Rect(0,0,m_nWidth,m_nHeight),0,
0,m_nWidth, m_nSliceHeight,UnitPixel);
}
// hover state
else if ( m_bHover )
{
m_pGraphics->DrawImage(m_pImage,Rect(0,0,m_nWidth,m_nHeight),0,
0,m_nWidth, m_nSliceHeight,UnitPixel);
}
// enable state
else
{
m_pGraphics->DrawImage(m_pImage,Rect(0,0,m_nWidth,m_nHeight),0,
0,m_nSliceWidth, m_nSliceHeight,UnitPixel);
}
}
有兴趣的话可以去下载这两个类:
http://download.csdn.net/detail/c__allen/4327358