Painting the Background for a CFormView Derived Class
Posted
by Adrian Roman
on August 5th, 1998
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: keithr@europa.com // 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