Painting the Background for a CFormView Derived Class

I wanted to paint bitmaps on forms, like Access does. So I wrote some code for that: First, add in your derived CFormView two members:


CPalette m_palette;
CBitmap m_bitmap;

Add the following functions to your derived class: OnDraw overrides the base class’ function, and OnCtlColor is a handler for WM_CTLCOLOR message. Call in OnInitialUpdate the function:

GetBitmapAndPalette( IDB_BACK, m_bitmap, m_palette );

where IDB_BACK is the identifier for the bitmap you want as background.

The code uses Keith Rule’s CMemDC class. I added it here, so you don’t have to search for it.

Add to your view a handler for WM_ERASEBKGND message:

BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return FALSE;
}

void CMyFormView::OnDraw(CDC* pDC)
{
// TODO: Add your specialized code here and/or call the base class
::DrawTheBackground(this,pDC,&m_palette,&m_bitmap);
}

HBRUSH CMyFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
//replace with your own base class
HBRUSH hbr = CDaoRecordView::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC here
if(nCtlColor==CTLCOLOR_STATIC){
//this is only an example – you may have to modify here the
//code in order to work properly for you
if(pWnd->GetDlgCtrlID()==IDC_STATIC){
pDC->SetBkMode(TRANSPARENT);
//you can change the color of static text here
//pDC->SetTextColor(RGB(255,255,255));
return (HBRUSH)::GetStockObject(NULL_BRUSH);
}
}else pDC->SetBkMode(OPAQUE);

// TODO: Return a different brush if the default is not desired
return hbr;
}

BOOL CMyFormView::GetBitmapAndPalette(UINT nIDResource,
CBitmap &bitmap,
CPalette &pal)
{
LPCTSTR lpszResourceName = (LPCTSTR)nIDResource;
HBITMAP hBmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION );
if( hBmp == NULL )return FALSE;
bitmap.Attach( hBmp );
// Create a logical palette for the bitmap
DIBSECTION ds;
BITMAPINFOHEADER &bmInfo = ds.dsBmih;
bitmap.GetObject( sizeof(ds), &ds );
int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1
<< bmInfo.biBitCount;
// Create a halftone palette if colors > 256.
CClientDC dc(NULL); // Desktop DC
if( nColors > 256 ) pal.CreateHalftonePalette( &dc );
else{
// Create the palette
RGBQUAD *pRGB = new RGBQUAD[nColors];
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject( &bitmap );
::GetDIBColorTable( memDC, 0, nColors, pRGB );
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY)
* nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
for( int i=0; i < nColors; i++){
pLP->palPalEntry[i].peRed = pRGB[i].rgbRed;
pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
pal.CreatePalette( pLP );
delete[] pLP;
delete[] pRGB;
}
return TRUE;
}

void DrawTheBackground(CDaoRecordView *view,
CDC *pDC,
CPalette *mp_palette,
CBitmap *mp_bitmap)
{
if(pDC->IsPrinting())return;
CRect rect;
CPalette *old_palette=NULL;
// Select and realize the palette
if( pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE &&
mp_palette->m_hObject != NULL ){
old_palette=pDC->SelectPalette( mp_palette, FALSE );
pDC->RealizePalette();
}
view->GetClientRect(rect);
pDC->DPtoLP(rect);
CMemDC DC(pDC,rect);
CDC dcImage;
if (!dcImage.CreateCompatibleDC(pDC))return;
BITMAP bm;
mp_bitmap->GetBitmap(&bm);
// Paint the image.
CBitmap* pOldBitmap = dcImage.SelectObject(mp_bitmap);
for(int i=((int)floor((double)rect.left/bm.bmWidth))*bm.bmWidth;
i<=rect.right/*rect.Width()*/;i+=bm.bmWidth)
for(int j=((int)floor((double)rect.top/bm.bmHeight))
*bm.bmHeight;j<=rect.bottom/*rect.Height()
*/;j+=bm.bmHeight)
DC->BitBlt(i, j, bm.bmWidth, bm.bmHeight, &dcImage,
0, 0, SRCCOPY);
dcImage.SelectObject(pOldBitmap);
pDC->SelectPalette(old_palette,FALSE);
pDC->RealizePalette();
}

#ifndef _MEMDC_H_
#define _MEMDC_H_
//////////////////////////////////////////////////
// CMemDC – memory DC
//
// Author: Keith Rule
// Email: [email protected]
// Copyright 1996-1997, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History – 10/3/97 Fixed scrolling bug.
// Added print support.
//
// This class implements a memory Device Context

class CMemDC : public CDC {
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
public:
CMemDC(CDC* pDC, CRect &rect) : CDC(), m_oldBitmap(NULL),
m_pDC(pDC)
{
ASSERT(m_pDC != NULL); // If you asserted here, you passed
// in a NULL CDC.
m_bMemDC = !pDC->IsPrinting();
m_rect=rect;
if (m_bMemDC){
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC->GetClipBox(&m_rect);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(),
m_rect.Height());
m_oldBitmap = SelectObject(&m_bitmap);
SetWindowOrg(m_rect.left, m_rect.top);
} else {
// Make a copy of the relevent parts of the current DC
// for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
}

~CMemDC()
{
if (m_bMemDC) {
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(),
m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_oldBitmap);
} else {
// All we need to do is replace the DC with an illegal
// value, this keeps us from accidently deleting the
// handles associated with the CDC that was passed to
// the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC* operator->() {return this;}
// Allow usage as a pointer
operator CMemDC*() {return this;}
};

#endif

More by Author

Must Read