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: 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


Comments

  • help me

    Posted by Legacy on 08/09/2000 12:00am

    Originally posted by: Ireber

    I have a problems to put a bitmap in a cformview derived class. Can any send my a project sample?

    Reply
  • Painting the background for a CFormView derived class

    Posted by Legacy on 01/24/2000 12:00am

    Originally posted by: Eugene

    Hi...i would like to comment regarding about the cooding being implemented in this website. The explaination is not clear at all and i really have no idea what are you trying to express true this codes. Please place a step by step explaination so that beginners will be able to understand it.


    Regards

    Eugene

    Reply
  • how can I organize this into one class?

    Posted by Legacy on 10/17/1999 12:00am

    Originally posted by: Erich Ruth

    I have a program with many CFormView's. To paint a bitmap in the CFormView background, I type the following:

    CView1::CView1() : CFormView(CView1::IDD)
    {
    m_HollowBrush.CreateStockObject(HOLLOW_BRUSH);
    //{{AFX_DATA_INIT(CView1)
    //}}AFX_DATA_INIT
    }

    BEGIN_MESSAGE_MAP(CView1, CFormView)
    ON_WM_ERASEBKGND()
    //{{AFX_MSG_MAP(CView1)
    ...
    ON_WM_CTLCOLOR()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    BOOL CView1::OnEraseBkgnd(CDC* pDC)
    { ... }

    HBRUSH CView1::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    { ... }

    I have lots and lots of CFormView's in my program. How can I create a single class which handles these commands for changing the background color? Currently, I have these commands in every CFormView I have.

    Your code is really cool, but I don't know how to condense it to a single class. Please, if you know of any way of reducing the above code to a single class and can show me where to then call it in OnInitDialog(), I would greatly appreciate a response. Or if you have a demo project of your code where the majority of the code is contained in a class, I would love to see it.

    Sincerely,
    Erich J. Ruth

    Reply
  • Selecting Palette with a NULL value

    Posted by Legacy on 09/10/1999 12:00am

    Originally posted by: Rob Cooney

    Hi,

    Ive tried this code in my application, and it works great on my '95 machine, but have found problems running the same code on NT and 2000..
    In the DrawTheBackground function
    if( pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) returns FALSE, and so old_palette is never given a value. Later in the function we re-select the old palette regardless pDC->SelectPalette(old_palette,FALSE);
    i.e
    pDC->SelectPalette(NULL,FALSE);

    altho windows allows this, it doesnt look like a good idea.

    Also on NT and 2000 my bitmap colors are slightly darker.

    any fixes??

    Reply
  • How to paint a bitmap as an OCX background when it is inactive

    Posted by Legacy on 04/29/1999 12:00am

    Originally posted by: arindam Bhattacharya

    We have created our own OCX to be inserted in word
    
    the problem is that when inactive we want to paint a bitmap
    I have asked to print a bitmap in the OnDraw function but only a red cross( maybe a default bitmap)comes up.
    but the bitmap is drawn when i db;lclick on the OCX ctrl and made it active. please let me know what to do to paint the background of an OCX when it is inactive

    Reply
  • another bug when minimize window and then restore it

    Posted by Legacy on 01/19/1999 12:00am

    Originally posted by: Beman

    do following below:
    1.right click the mouse
    2.hide the output window
    3.minimize the mainframe window
    4.then restore it
    5.you will find that the WorkSpace display grey
    now,it's very clearly,there must be a bug.
    I only know a little English,so if you
    can't understand me clearly.I'm sorry for that.
    that's all.I hope someone can solve it.that will
    be a useful work for everyone who use this lib.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds