主要通过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; }
下面是主要内容:建立PNGButton类的实现方法一:
该类继承与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); } }
有兴趣的话可以去下载这两个类: