An auto-sizing bitmap picture control

The Picture control available from the dialog editor component bar is great for quickly displaying a picture in a dialog, but it only displays the picture at the original picture's size. A problem occurs if you want to display a bitmap which must be aligned with other controls (eg. a bitmap of an arrow). If you change the size of the dialog box font, then the size and position of each control will also change, but the size of the displayed bitmap will not, resulting in a mis-aligned picture. The problem also occurs if the system font size is changed (The matrox millenium drivers allow you to do this).
To overcome this problem I wrote a CStatic derived class that displays a bitmap according to the size of the underlying CStatic window. When the font size changes, the CStatic window size changes, and the bitmap will be StretchBlt'd to the new size. This allows images to be displayed smaller and larger than their original size.
BOOL SetBitmap(UINT nIDResource); // Loads bitmap from resource ID BOOL SetBitmap(LPCTSTR lpszResourceName); // Loads bitmap from resource name BOOL SetBitmap(HBITMAP hBitmap); // Not recommended, as reloads can't be done
The implementation handles the SYSCOLORCHANGE message as described by
Pel K. Txnder in his article
//www.codeguru.com/misc/syscol_static.shtml"> CStatic with bitmap
sensitive to change in system colours.
Source:
#if !defined(AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_) #define AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // BitmapPicture.h : header file // // Copyright (c) Chris Maunder (Chris.Maunder@cbr.clw.csiro.au) // Written 1 December, 1997 ///////////////////////////////////////////////////////////////////////////// // CBitmapPicture window class CBitmapPicture : public CStatic { // Construction public: CBitmapPicture(); // Operations public: BOOL SetBitmap(HBITMAP hBitmap); // Not recommended BOOL SetBitmap(UINT nIDResource); BOOL SetBitmap(LPCTSTR lpszResourceName); BOOL ReloadBitmap(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CBitmapPicture) protected: virtual void PreSubclassWindow(); virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); //}}AFX_VIRTUAL // Implementation public: virtual ~CBitmapPicture(); // Attributes protected: HBITMAP m_hBitmap; BITMAP m_bmInfo; private: int m_nResourceID; CString m_strResourceName; // Generated message map functions protected: //{{AFX_MSG(CBitmapPicture) afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnSysColorChange(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_) // BitmapPicture.cpp : implementation file // // Copyright (c) 1997 Chris Maunder (Chris.Maunder@cbr.clw.csiro.au) // Written 1 December, 1997 #include "stdafx.h" #include "BitmapPicture.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // if UPDATE_ENTIRE_CLIENT_AREA is not defined then only the update region of // the bitmap is updated. Otherwise, on each update, the whole client area of // the bitmap is drawn. UPDATE_ENTIRE_CLIENT_AREA is slower, but distortion // of the picture may occur if it is not defined. #define UPDATE_ENTIRE_CLIENT_AREA ///////////////////////////////////////////////////////////////////////////// // CBitmapPicture CBitmapPicture::CBitmapPicture() { m_hBitmap = NULL; m_nResourceID = -1; m_strResourceName.Empty(); } CBitmapPicture::~CBitmapPicture() { if (m_hBitmap) ::DeleteObject(m_hBitmap); } BEGIN_MESSAGE_MAP(CBitmapPicture, CStatic) //{{AFX_MSG_MAP(CBitmapPicture) ON_WM_ERASEBKGND() ON_WM_DRAWITEM_REFLECT() ON_WM_SYSCOLORCHANGE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CBitmapPicture message handlers BOOL CBitmapPicture::SetBitmap(HBITMAP hBitmap) { ::DeleteObject(m_hBitmap); m_hBitmap = hBitmap; return ::GetObject(m_hBitmap, sizeof(BITMAP), &m_bmInfo); } BOOL CBitmapPicture::SetBitmap(UINT nIDResource) { m_nResourceID = nIDResource; m_strResourceName.Empty(); HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource), IMAGE_BITMAP, 0,0, LR_LOADMAP3DCOLORS); if (!hBmp) return FALSE; return CBitmapPicture::SetBitmap(hBmp); } BOOL CBitmapPicture::SetBitmap(LPCTSTR lpszResourceName) { m_nResourceID = -1; m_strResourceName = lpszResourceName; HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), lpszResourceName, IMAGE_BITMAP, 0,0, LR_LOADMAP3DCOLORS); if (!hBmp) return FALSE; return CBitmapPicture::SetBitmap(hBmp); } // Suggested by Pel K. Used to reload the bitmap on system colour changes. BOOL CBitmapPicture::ReloadBitmap() { if (m_nResourceID > 0) return SetBitmap(m_nResourceID); else if (!m_strResourceName.IsEmpty()) return SetBitmap(m_strResourceName); else // if SetBitmap(HBITMAP hBitmap) was used directly then we can't reload. return FALSE; } void CBitmapPicture::PreSubclassWindow() { CStatic::PreSubclassWindow(); ModifyStyle(0, SS_OWNERDRAW); } BOOL CBitmapPicture::OnEraseBkgnd(CDC* pDC) { CRect rect; GetClientRect(rect); // If no bitmap selected, simply erase the background as per normal and return if (!m_hBitmap) { CBrush backBrush(::GetSysColor(COLOR_3DFACE)); // (this is meant for dialogs) CBrush* pOldBrush = pDC->SelectObject(&backBrush); pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); pDC->SelectObject(pOldBrush); return TRUE; } // We have a bitmap - draw it. // Create compatible memory DC using the controls DC CDC dcMem; VERIFY( dcMem.CreateCompatibleDC(pDC)); // Select bitmap into memory DC. HBITMAP* pBmpOld = (HBITMAP*) ::SelectObject(dcMem.m_hDC, m_hBitmap); // StretchBlt bitmap onto static's client area #ifdef UPDATE_ENTIRE_CLIENT_AREA pDC->StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, m_bmInfo.bmWidth-1, m_bmInfo.bmHeight-1, SRCCOPY); #else CRect TargetRect; // Region on screen to be updated pDC->GetClipBox(&TargetRect); TargetRect.IntersectRect(TargetRect, rect); CRect SrcRect; // Region from bitmap to be painted SrcRect.left = MulDiv(TargetRect.left, m_bmInfo.bmWidth, rect.Width()); SrcRect.top = MulDiv(TargetRect.top, m_bmInfo.bmHeight, rect.Height()); SrcRect.right = MulDiv(TargetRect.right, m_bmInfo.bmWidth, rect.Width()); SrcRect.bottom = MulDiv(TargetRect.bottom, m_bmInfo.bmHeight, rect.Height()); pDC->StretchBlt(TargetRect.left, TargetRect.top, TargetRect.Width(), TargetRect.Height(), &dcMem, SrcRect.left, SrcRect.top, SrcRect.Width(), SrcRect.Height(), SRCCOPY); #endif ::SelectObject(dcMem.m_hDC, pBmpOld); return TRUE; } void CBitmapPicture::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { ASSERT(lpDrawItemStruct != NULL); CString str; GetWindowText(str); if (!str.GetLength()) return; CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); CRect rect = lpDrawItemStruct->rcItem; DWORD dwStyle = GetStyle(); int nFormat = DT_NOPREFIX | DT_NOCLIP | DT_WORDBREAK | DT_SINGLELINE; if (dwStyle & SS_CENTERIMAGE) nFormat |= DT_VCENTER; if (dwStyle & SS_CENTER) nFormat |= DT_CENTER; else if (dwStyle & SS_RIGHT) nFormat |= DT_RIGHT; else nFormat |= DT_LEFT; int nOldMode = pDC->SetBkMode(TRANSPARENT); pDC->DrawText(str, rect, nFormat); pDC->SetBkMode(nOldMode); } // Suggested by Pel K. Txnder. void CBitmapPicture::OnSysColorChange() { CStatic::OnSysColorChange(); ReloadBitmap(); }
Comments
Need help urgent
Posted by Kalyani Homkar on 06/10/2015 06:21amHi All, I am trying the below scenario since a long time but unable to succeed. Inputs: Dialog box with 2 Picture controls, mfcbutton, slider control and few buttons. 1. I need to add a jpg image as complete background of my dialog box. Solution: I have achieved this by using CImagePreviewStatic. Below is the link: https://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CCMQFjABahUKEwiehpHWmYXGAhULq7wKHeNQABo&url=http://www.codeproject.com/Articles/6354/A-simple-image-preview-class-using-GDI&ei=XDd4VZ7oMovW8gXjoYHQAQ&usg=AFQjCNEcO0kiW8Ie-voNfaGMIDB2P3D0Ig&bvm=bv.95039771,d.dGc&cad=rja[^] This is working fine for me. 2. 2nd picture control is positioned centered on top of 1st- I have an Bitmap attached or I draw a graph like temperature measurement etc using OnPaint() with SolidBrush to draw polylines etc. Based on the Slider control input, I now want to make this 2nd picture control transparent in a way that it fades to some maximum value. Also, the mfcbutton that I mentioned is having a bitmap added, even its transparency should change with respect to slider control value. I am using Visual Studio 2010 and MFC C++ only. Please let me know if you are aware of any solutions. Thank you in advance.
ReplyDrawing on CStatic PictureBoxControl in evc
Posted by Legacy on 06/07/2002 12:00amOriginally posted by: Gaurav
How to use to add the background bitmap for property page
Posted by Legacy on 05/14/2002 12:00amOriginally posted by: shashi
Hello frinds,
I would like to add bitmap as a background in property page
so hiw i supposed to add bitmap in property page.(i'm using CPropertypage class)
thanks in advance,
Replyshashi
A new Method
Posted by Legacy on 02/10/2002 12:00amOriginally posted by: Gasparote
File Support
Posted by Legacy on 08/29/2001 12:00amOriginally posted by: Ken
To load a file
Posted by Legacy on 12/13/2000 12:00amOriginally posted by: Thorben Stangenberg
Just use the
BOOL CBitmapPicture::SetBitmap(LPCTSTR lpszResourceName)
method and set lpszResourceName to your Filename.
Change the LoadImage function to this
HBITMAP hBmp = (HBITMAP)::LoadImage(
AfxGetResourceHandle(), lpszResourceName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
Thank's for the great little tutorial
Posted by Legacy on 08/29/2000 12:00amOriginally posted by: Tom
This is the information I needed. And I found the tutorial style especially helpful. Thanks a bunch.
ReplyFile Support?
Posted by Legacy on 08/18/2000 12:00amOriginally posted by: Tom Russell
I would like to be able to load images from files, also. It would really be nice if I could implement drag/drop, but this may require OLE.
ReplyQuestion: File Support?
Posted by Legacy on 09/22/1999 12:00amOriginally posted by: Clifford
Will loading and switching the bitmaps from files be easily supported?
Thanks
Clifford
Reply
Little correction
Posted by Legacy on 05/28/1999 12:00amOriginally posted by: Adeluc