出自ProgWiki
用途
- 圖形化按鈕類別,擴充自 MFC 的 CBitmapButton。
- (改透過元件 IPicture 來載入圖檔,故可支援較多種的圖檔格式。)
原始程式
ImageButton.h
#pragma once
//-----------------------------------------------------------------------------
//class CImageButton 編譯相關開關
//#define CImageButton_UseCOM 1
#define CImageButton_UseFile 1
//#define CImageButton_UseResource 1
//-----------------------------------------------------------------------------
//class CImageButton
// 使用 IPicture 對圖檔解碼
// 支援圖檔格式
// JPG(jpeg), GIF, BMP (bitmap), WMF (metafile), ICO (icon)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 路徑合併用 ( PathAppend 與 PathCombine )
//-----------------------------------------------------------------------------
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
inline void PathAppend(CString& strPath, LPCTSTR lpszMore)
{
//TODO: PathAppend(CString& strPath, LPCTSTR lpszMore)
::PathAppend( strPath.GetBuffer(MAX_PATH),
lpszMore);
strPath.ReleaseBuffer();
}
inline void PathCombine(CString& strDest, LPCTSTR lpszDir, LPCTSTR lpszFile)
{
//TODO: PathCombine(CString& strDest, LPCTSTR lpszDir, LPCTSTR lpszFile)
::PathCombine( strDest.GetBuffer(MAX_PATH),
lpszDir,
lpszFile);
strDest.ReleaseBuffer();
}
//-----------------------------------------------------------------------------
// CImageButton
// 圖形化按鈕類別, 繼承自 MFC 的 CBitmapButton
//
// 類別繼承樹
// CObject +
// + CCmdTarget +
// + CWnd +
// + CButton +
// + CBitmapButton +
// + CImageButton
//-----------------------------------------------------------------------------
//class CBitmapButton
#include <afxctl.h>
class CImageButton : public CBitmapButton
{
DECLARE_DYNAMIC(CImageButton)
public:
CImageButton();
virtual ~CImageButton();
protected:
DECLARE_MESSAGE_MAP()
BOOL m_bTracking;
virtual void PreSubclassWindow();
public:
//滑鼠移入事件
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
//滑鼠移出事件
afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM);
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseCOM
#ifdef CImageButton_UseCOM
public:
//COM初始化
static void InitRunTimeEnvironment(void);
//COM釋放
static void ReleaseRunTimeEnvironment(void);
#endif
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseResource
#ifdef CImageButton_UseResource
protected:
//For Resource
static HINSTANCE m_hInstance;
static LPCSTR m_lpszType;
HRESULT GetImageFromResource(LPCTSTR lpszFilename, IPicture** ppPicture);
HRESULT GetImageToBitmapFromResource(CBitmap& bmp, LPCTSTR lpszFilename);
public:
//設定Resource來源預設
static void SetImageResource(HINSTANCE hInstance, LPCSTR lpszType);
// 從Resource裡載入圖檔
HRESULT LoadImagesFromResource(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel = NULL, LPCTSTR lpszImageFileFocus = NULL, LPCTSTR lpszImageFileDisabled = NULL);
#endif
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseFile
#ifdef CImageButton_UseFile
protected:
//For檔案
static CString m_strImagePath;
HRESULT GetImageFromFile(LPCTSTR lpszFilename, IPicture** ppPicture);
HRESULT GetImageToBitmapFromFile(CBitmap& bmp, LPCTSTR lpszFilename);
public:
//設定檔案來源預設路徑
static void SetImagePath(LPCTSTR lpszImagePath);
// 從檔案載入圖檔
HRESULT LoadImagesFromFile(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel = NULL, LPCTSTR lpszImageFileFocus = NULL, LPCTSTR lpszImageFileDisabled = NULL);
#endif
};
ImageButton.cpp
// ImageButton.cpp : 實作檔
//
#include "stdafx.h"
#include "ImageButton.h"
// CImageButton
IMPLEMENT_DYNAMIC(CImageButton, CBitmapButton)
//建構
CImageButton::CImageButton()
: m_bTracking(FALSE)
{
//TODO: CImageButton()
}
//解構
CImageButton::~CImageButton()
{
//TODO: ~CImageButton()
}
//視窗訊息對應函式映射表
BEGIN_MESSAGE_MAP(CImageButton, CBitmapButton)
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
void CImageButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: OnMouseMove(UINT nFlags, CPoint point)
//TRACE("\nOnMouseMove ( %d, %d )", point.x, point.y );
CBitmapButton::OnMouseMove(nFlags, point);
if (this->GetFocus() != this)
{
this->SetFocus();
TRACE("\nOnMouseMove ( %d, %d )", point.x, point.y );
if (m_bTracking == FALSE)
{
TRACKMOUSEEVENT t =
{
sizeof(TRACKMOUSEEVENT),
TME_LEAVE,
this->GetSafeHwnd(),
0
};
if (::_TrackMouseEvent(&t))
{
TRACE("\n* Mouse Enter");
m_bTracking = TRUE;
//按鈕重繪
Invalidate();
}
}
}
}
LRESULT CImageButton::OnMouseLeave(WPARAM, LPARAM)
{
//TODO: OnMouseLeave(WPARAM, LPARAM)
TRACE("\nOnMouseLeave");
if (m_bTracking == TRUE)
{
TRACKMOUSEEVENT t =
{
sizeof(TRACKMOUSEEVENT),
TME_CANCEL,
this->GetSafeHwnd(),
0
};
if (::_TrackMouseEvent(&t))
{
TRACE("\n* Mouse Leave");
m_bTracking = FALSE;
}
}
#if 0
//單一層視窗用
POINT pt;
GetCursorPos(&pt);
HWND hWnd = ::WindowFromPoint(pt);
::SetFocus(hWnd);
#else
//多層視窗用
::SetFocus(::AfxGetApp()->GetMainWnd()->GetSafeHwnd());
#endif
//按鈕重繪
Invalidate();
return S_OK;
}
void CImageButton::PreSubclassWindow()
{
// TODO: PreSubclassWindow()
CBitmapButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);
}
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseCOM
#ifdef CImageButton_UseCOM
//初始化COM
void CImageButton::InitRunTimeEnvironment(void)
{
//TODO: InitRunTimeEnvironment(void)
CoInitialize(NULL);
}
//釋放COM
void CImageButton::ReleaseRunTimeEnvironment(void)
{
//TODO: ReleaseRunTimeEnvironment(void)
CoUninitialize();
}
#endif
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseFile
#ifdef CImageButton_UseFile
CString CImageButton::m_strImagePath = _T("");
//設定檔案來源預設路徑
void CImageButton::SetImagePath(LPCTSTR lpszImagePath)
{
//TODO: SetImagePath(LPCTSTR lpszImagePath)
TRACE("\n*設定圖檔預設路徑: %s\n", m_strImagePath);
m_strImagePath = lpszImagePath;
}
//載入圖檔到 IPicture
HRESULT CImageButton::GetImageFromFile(LPCTSTR lpszFilename, IPicture** ppPicture)
{
//TODO: GetImageFromFile(LPCTSTR pstrFilename, IPicture** ppPicture)
if (*ppPicture)
*ppPicture = NULL;
if (lpszFilename == NULL)
return E_NOINTERFACE;
IPicture *pPic;
CComPtr<IStream> pStm = NULL;
BOOL bResult;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwFileSize = 0,
dwByteRead = 0;
HGLOBAL hGlobal = NULL;
LPVOID pvData = NULL;
try
{
hFile = CreateFile( lpszFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return E_NOINTERFACE;
dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize == 0xFFFFFFFF)
throw S_FALSE;
hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
if (hGlobal == NULL)
throw S_FALSE;
if ((pvData = GlobalLock(hGlobal)) == NULL)
throw S_FALSE;
ReadFile(hFile,pvData,dwFileSize,&dwByteRead,NULL);
if (CloseHandle(hFile) != NULL)
hFile = INVALID_HANDLE_VALUE;
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
bResult = OleLoadPicture( pStm,
dwFileSize,
TRUE,
IID_IPicture,
(LPVOID*)&pPic);
if (FAILED(bResult))
throw S_FALSE;
*ppPicture = pPic;
}
catch(HRESULT)
{
if (hGlobal)
{
if (pvData)
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT CImageButton::GetImageToBitmapFromFile(CBitmap& bmp, LPCTSTR lpszFilename)
{
//TODO: GetImageToBitmapFromFile(CBitmap& bmp, LPCTSTR lpszFilename)
if (lpszFilename == NULL)
return S_FALSE;
CString strImageFile;
strImageFile = lpszFilename;
if (strImageFile.Find(_T(':')) == -1)
{
if (!m_strImagePath.IsEmpty())
PathCombine(strImageFile, m_strImagePath, lpszFilename);
}
CPictureHolder PictureHolder;
HRESULT hr = S_FALSE;
IPicture* pPicture = NULL;
hr = this->GetImageFromFile(strImageFile, &pPicture);
if (SUCCEEDED(hr))
{
OLE_XSIZE_HIMETRIC nWidth;
OLE_YSIZE_HIMETRIC nHeight;
pPicture->get_Width(&nWidth);
pPicture->get_Height(&nHeight);
nWidth = (int)((float)nWidth / 26.46f);
nHeight = (int)((float)nHeight / 26.46f);
CRect rcBounds(0, 0, nWidth, nHeight);
CClientDC dc0( CWnd::GetDesktopWindow());
CDC dc;
dc.CreateCompatibleDC( &dc0 );
bmp.CreateCompatibleBitmap( &dc0, nWidth, nHeight );
CBitmap* pBmpOld = (CBitmap*) dc.SelectObject(bmp);
PictureHolder.m_pPict = pPicture;
PictureHolder.Render(&dc, rcBounds, rcBounds);
PictureHolder.m_pPict = NULL;
pPicture->Release();
//dc.SelectObject(pBmpOld);
return S_OK;
}
return S_FALSE;
}
// 從檔案載入圖檔
HRESULT CImageButton::LoadImagesFromFile(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel, LPCTSTR lpszImageFileFocus, LPCTSTR lpszImageFileDisabled)
{
//TODO: LoadImagesFromFile(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel, LPCTSTR lpszImageFileFocus, LPCTSTR lpszImageFileDisabled)
m_bitmap.DeleteObject();
m_bitmapSel.DeleteObject();
m_bitmapFocus.DeleteObject();
m_bitmapDisabled.DeleteObject();
HRESULT hr = S_OK;
//圖檔載入
if (lpszImageFile)
{
hr = GetImageToBitmapFromFile(m_bitmap, lpszImageFile);
if (hr != S_OK)
{
TRACE("\n*無法載入圖檔: %s\n按鈕顯示自動進入純文字模式\n", lpszImageFile);
ModifyStyle( BS_OWNERDRAW, 0);
return S_FALSE;
}
}
if (lpszImageFileSel)
{
hr = GetImageToBitmapFromFile(m_bitmapSel, lpszImageFileSel);
}
if (lpszImageFileFocus)
{
hr = GetImageToBitmapFromFile(m_bitmapFocus, lpszImageFileFocus);
}
if (lpszImageFileDisabled)
{
hr = GetImageToBitmapFromFile(m_bitmapDisabled, lpszImageFileDisabled);
}
//按鈕自動縮放到圖檔的Size
this->SizeToContent();
return S_OK;
}
#endif
//-----------------------------------------------------------------------------
//TODO: #ifdef CImageButton_UseResource
#ifdef CImageButton_UseResource
HINSTANCE CImageButton::m_hInstance = NULL;
LPCSTR CImageButton::m_lpszType = RT_HTML;
void CImageButton::SetImageResource(HINSTANCE hInstance, LPCSTR lpszType)
{
//TODO: SetImageResource(HINSTANCE hInstance, LPCSTR lpszType)
m_hInstance = hInstance;
m_lpszType = lpszType;
}
//載入圖檔到 IPicture
HRESULT CImageButton::GetImageFromResource(LPCTSTR lpszFilename, IPicture** ppPicture)
{
//TODO: GetImageFromResource(LPCTSTR pstrFilename, IPicture** ppPicture)
if (*ppPicture)
*ppPicture = NULL;
if (lpszFilename == NULL)
return E_NOINTERFACE;
IPicture *pPic;
CComPtr<IStream> pStm = NULL;
BOOL bResult;
HRSRC hResInfo = NULL;
HGLOBAL hRes = NULL;
char* lpRes = NULL;
DWORD dwFileSize = 0;
HGLOBAL hGlobal = NULL;
LPVOID pvData = NULL;
try
{
hResInfo = FindResource(m_hInstance, lpszFilename, m_lpszType);
if (hResInfo == NULL)
throw S_FALSE;
dwFileSize = SizeofResource( m_hInstance, hResInfo );
if (dwFileSize == 0)
throw S_FALSE;
hRes = LoadResource(m_hInstance, hResInfo );
if (hRes == NULL)
throw S_FALSE;
hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
if (hGlobal == NULL)
throw S_FALSE;
if ((pvData = GlobalLock(hGlobal)) == NULL)
throw S_FALSE;
lpRes = (char*)LockResource(hRes);
if (lpRes)
{
CopyMemory(pvData, lpRes, dwFileSize);
UnlockResource(hRes);
lpRes = NULL;
}
if (FreeResource(hRes) == NULL)
hRes = NULL;
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
bResult = OleLoadPicture( pStm,
dwFileSize,
TRUE,
IID_IPicture,
(LPVOID*)&pPic);
if (FAILED(bResult))
throw S_FALSE;
*ppPicture = pPic;
}
catch(HRESULT)
{
if (hGlobal)
{
if (pvData)
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
}
if (hRes)
{
if (lpRes)
UnlockResource(hRes);
FreeResource(hRes);
}
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT CImageButton::GetImageToBitmapFromResource(CBitmap& bmp, LPCTSTR lpszFilename)
{
//TODO: GetImageToBitmapFromFile(CBitmap& bmp, LPCTSTR lpszFilename)
if (lpszFilename == NULL)
return S_FALSE;
CPictureHolder PictureHolder;
HRESULT hr = S_FALSE;
IPicture* pPicture = NULL;
hr = this->GetImageFromResource(lpszFilename, &pPicture);
if (SUCCEEDED(hr))
{
OLE_XSIZE_HIMETRIC nWidth;
OLE_YSIZE_HIMETRIC nHeight;
pPicture->get_Width(&nWidth);
pPicture->get_Height(&nHeight);
nWidth = (int)((float)nWidth / 26.46f);
nHeight = (int)((float)nHeight / 26.46f);
CRect rcBounds(0, 0, nWidth, nHeight);
CClientDC dc0( CWnd::GetDesktopWindow());
CDC dc;
dc.CreateCompatibleDC( &dc0 );
bmp.CreateCompatibleBitmap( &dc0, nWidth, nHeight );
CBitmap* pBmpOld = (CBitmap*) dc.SelectObject(bmp);
PictureHolder.m_pPict = pPicture;
PictureHolder.Render(&dc, rcBounds, rcBounds);
PictureHolder.m_pPict = NULL;
pPicture->Release();
//dc.SelectObject(pBmpOld);
return S_OK;
}
return S_FALSE;
}
// 從Resource裡載入圖檔
HRESULT CImageButton::LoadImagesFromResource(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel, LPCTSTR lpszImageFileFocus, LPCTSTR lpszImageFileDisabled)
{
//TODO: LoadImagesFromResource(LPCTSTR lpszImageFile, LPCTSTR lpszImageFileSel, LPCTSTR lpszImageFileFocus, LPCTSTR lpszImageFileDisabled)
m_bitmap.DeleteObject();
m_bitmapSel.DeleteObject();
m_bitmapFocus.DeleteObject();
m_bitmapDisabled.DeleteObject();
HRESULT hr = S_OK;
//圖檔載入
if (lpszImageFile)
{
hr = GetImageToBitmapFromResource(m_bitmap, lpszImageFile);
if (hr != S_OK)
{
TRACE("\n*無法載入圖檔: %s\n按鈕顯示自動進入純文字模式\n", lpszImageFile);
ModifyStyle( BS_OWNERDRAW, 0);
return S_FALSE;
}
}
if (lpszImageFileSel)
{
hr = GetImageToBitmapFromResource(m_bitmapSel, lpszImageFileSel);
}
if (lpszImageFileFocus)
{
hr = GetImageToBitmapFromResource(m_bitmapFocus, lpszImageFileFocus);
}
if (lpszImageFileDisabled)
{
hr = GetImageToBitmapFromResource(m_bitmapDisabled, lpszImageFileDisabled);
}
//按鈕自動縮放到圖檔的Size
this->SizeToContent();
return S_OK;
}
#endif