📄 bmpbutsdlg.cpp
字号:
// BmpButsDlg.cpp : implementation file
//
// Step 1. Create as many picture controls as you wish and set the flags Tab stop
// and Notify. In this application they are: IDC_STATIC_TEXT, IDC_STATIC_DATE,
// IDC_STATIC_EXIT.
// Step 2. With (recomended) or without Class Wizard create a new class, derived
// from CStatic. In this application it is CBmpButton
// Step 3. With Class Wizard add member variables for each of the picture controls.
// The Category will be "Control" and the Variable type the name of your new class
// In this application these variables are: m_textButton, m_dateButton, m_exitButton
// Step 4. Init the controls in the OnInitDialog with the LoadButtonBitmaps member
// function. You can enumerate here the bitmaps you wish to use
// Additional step 5. Add member function OnMouseMove (WM_MOUSEMOVE) to reset the
// buttons, whenever the loose the mouse cursor
#include "stdafx.h"
#include "BmpButs.h"
#include "BmpButsDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBmpButsDlg dialog
CBmpButsDlg::CBmpButsDlg(CWnd* pParent /*=NULL*/)
: CDialog(CBmpButsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CBmpButsDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CBmpButsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBmpButsDlg)
DDX_Control(pDX, IDC_STATIC_TEXT, m_textButton);
DDX_Control(pDX, IDC_STATIC_EXIT, m_exitButton);
DDX_Control(pDX, IDC_STATIC_DATE, m_dateButton);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CBmpButsDlg, CDialog)
//{{AFX_MSG_MAP(CBmpButsDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_STATIC_EXIT, OnStaticExit)
ON_BN_CLICKED(IDC_STATIC_DATE, OnStaticDate)
ON_BN_CLICKED(IDC_STATIC_TEXT, OnStaticText)
ON_WM_MOUSEMOVE()
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/***************************************************/
/* David Gallardo Llopis */
/* */
/* Based on the code in the book */
/* PROGRAMACION AVANZADA EN WINDOWS 2000 */
/* at McGraw-Hill (c) 2000 */
/* by */
/* J. Pascual, F. Charte, M.J. Segarra, */
/* J.A. Clavijo, A. de Antonio. */
/* */
/* The code in this book is based on an original */
/* code by Jean-Edouard Lachand-Robert */
/***************************************************/
HRGN CBmpButsDlg::BitmapRegion(HBITMAP hBitmap,COLORREF cTransparentColor,BOOL bIsTransparent)
{
// We create an empty region
HRGN hRegion=NULL;
// If the passed bitmap is NULL, go away!
if(!hBitmap)
return hRegion;
// We create a memory context for working with the bitmap
// The memory context is compatible with the display context (screen)
HDC hMemDC=CreateCompatibleDC(NULL);
// If no context is created, go away, too!
if(!hMemDC)
return hRegion;
// Computation of the bitmap size
BITMAP bmBitmap;
GetObject(hBitmap, sizeof(bmBitmap), &bmBitmap);
// In order to make the space for the region, we
// create a bitmap with 32bit depth color and with the
// size of the loaded bitmap!
BITMAPINFOHEADER RGB32BITSBITMAPINFO=
{
sizeof(BITMAPINFOHEADER),
bmBitmap.bmWidth,
bmBitmap.bmHeight,
1,32,BI_RGB,0,0,0,0,0
};
// Here is the pointer to the bitmap data
VOID *pBits;
// With the previous information, we create the new bitmap!
HBITMAP hNewBitmap;
hNewBitmap=CreateDIBSection(hMemDC,
(BITMAPINFO *)&RGB32BITSBITMAPINFO,
DIB_RGB_COLORS,&pBits,NULL,0);
// If the creation process succeded...
if(hNewBitmap)
{
// We select the bitmap onto the created memory context
// and then we store the previosly selected bitmap on this context!
HBITMAP hPrevBmp=(HBITMAP) SelectObject(hMemDC,hNewBitmap);
// We create another device context compatible with the first!
HDC hDC=CreateCompatibleDC(hMemDC);
// If success...
if(hDC)
{
// We compute the number of bytes per row that the bitmap contains, rounding to 32 bit-multiples
BITMAP bmNewBitmap;
GetObject(hNewBitmap,sizeof(bmNewBitmap),&bmNewBitmap);
while(bmNewBitmap.bmWidthBytes % 4)
bmNewBitmap.bmWidthBytes++;
// Copy of the original bitmap on the memory context!
HBITMAP hPrevBmpOrg=(HBITMAP) SelectObject(hDC,hBitmap);
BitBlt(hMemDC,0,0,bmBitmap.bmWidth,bmBitmap.bmHeight,hDC,0,0,SRCCOPY);
// In order to optimize the code, we don't call the GDI each time we
// find a transparent pixel. We use a RGN_DATA structure were we store
// consecutive rectangles, until we have a large amount of them and then we crete
// the composed region with ExtCreateRgn(), combining it with the main region.
// Then we begin again initializing the RGN_DATA structure and doing another
// iteration, until the entire bitmap is analyzed.
// Also, in order to not saturate the Windows API with calls for reserving
// memory, we wait until NUMRECT rectangles are stores in order to claim
// for another NUMRECT memory space!
#define NUMRECT 100
DWORD maxRect = NUMRECT;
// We create the memory data
HANDLE hData=GlobalAlloc(GMEM_MOVEABLE,sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRect));
RGNDATA *pData=(RGNDATA*) GlobalLock(hData);
pData->rdh.dwSize=sizeof(RGNDATAHEADER);
pData->rdh.iType=RDH_RECTANGLES;
pData->rdh.nCount=pData->rdh.nRgnSize=0;
SetRect(&pData->rdh.rcBound,MAXLONG,MAXLONG,0,0);
// We study each pixel on the bitmap...
BYTE *Pixeles=(BYTE*) bmNewBitmap.bmBits+(bmNewBitmap.bmHeight-1)*bmNewBitmap.bmWidthBytes;
// Main loop
for(int Row=0;Row<bmBitmap.bmHeight;Row++)
{
// Horizontal loop
for(int Column=0;Column<bmBitmap.bmWidth;Column++)
{
// We optimized searching for adyacent transparent pixels!
int Xo=Column;
LONG *Pixel=(LONG*) Pixeles+Column;
while(Column<bmBitmap.bmWidth)
{
BOOL bInRange=FALSE;
// If the color is that indicated as transparent...
if( GetRValue(*Pixel)==GetRValue(cTransparentColor) &&
GetGValue(*Pixel)==GetGValue(cTransparentColor) &&
GetBValue(*Pixel)==GetBValue(cTransparentColor) )
bInRange=TRUE;
if((bIsTransparent) && (bInRange))
break;
if((!bIsTransparent) && (!bInRange))
break;
Pixel++;
Column++;
} // while (Column < bm.bmWidth)
if(Column>Xo)
{
// We add the rectangle (Xo,Row),(Column,Row+1) to the region
// If the number of rectangles is greater then NUMRECT, we claim
// another pack of NUMRECT memory places!
if (pData->rdh.nCount>=maxRect)
{
GlobalUnlock(hData);
maxRect+=NUMRECT;
hData=GlobalReAlloc(hData,sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRect),GMEM_MOVEABLE);
pData=(RGNDATA *)GlobalLock(hData);
}
RECT *pRect=(RECT*) &pData->Buffer;
SetRect(&pRect[pData->rdh.nCount],Xo,Row,Column,Row+1);
if(Xo<pData->rdh.rcBound.left)
pData->rdh.rcBound.left=Xo;
if(Row<pData->rdh.rcBound.top)
pData->rdh.rcBound.top=Row;
if(Column>pData->rdh.rcBound.right)
pData->rdh.rcBound.right=Column;
if(Row+1>pData->rdh.rcBound.bottom)
pData->rdh.rcBound.bottom=Row+1;
pData->rdh.nCount++;
// In Win95/08 there is a limitation on the maximum number of
// rectangles a RGN_DATA can store (aprox. 4500), so we call
// the API for a creation and combination with the main region
// each 2000 rectangles. This is a good optimization, because
// instead of calling the routines for combining for each new
// rectangle found, we call them every 2000 rectangles!!!
if(pData->rdh.nCount==2000)
{
HRGN hNewRegion=ExtCreateRegion(NULL,sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRect),pData);
if (hNewRegion) {
// Si ya existe la regi髇 principal,sumamos la nueva,
// si no,entonces de momento la principal coincide con
// la nueva regi髇.
if (hRegion) {
CombineRgn(hRegion,hRegion,hNewRegion,RGN_OR);
DeleteObject(hNewRegion);
} else
hRegion=hNewRegion;
}
// Volvemos a comenzar la suma de rect醤gulos
pData->rdh.nCount=0;
SetRect(&pData->rdh.rcBound,MAXLONG,MAXLONG,0,0);
}
} // if (Column > Xo)
} // for (int Column ...)
// Nueva Row. Lo del negativo se debe a que el bitmap est
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -