StatusBar on Dialogs

MFC allows you to easily add status bars to CFrameWnd-derived windows.
However, if you want to add a status bar to a dialog, you’re going to find the
going just a bit more difficult.

Basically, it turned out that I had to dig very deep into the MFC documentation
in order to find anything to help me out. One example I found is by ZEKSER
Cyril. His techniques works fine, but (IMHO) is not very "clean"
since you have to place an invisible static object on the dialog as a kind of
placeholder for the status bar. However, I do want to thank him very much for
showing me the light at the end of the tunnel.

The technique I came up with works like this: First, you need to develop your
dialog (and define its CDialog-based class). Nothing new here so far.

Then, insert the following code into the CDialog::OnInitDialog function
(the m_StatBar variable is of type CStatusBarCtrl).


BOOL CMyDlg::OnInitDialog()
{
	CDialog::OnInitDialog();


	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

/************************************************************************/
/*		Adding STATUSBAR												*/
/************************************************************************/

	int nTotWide;		// total width of status bar

	CRect rect;
   	 this->GetWindowRect(&rect);
	 rect.top = rect.bottom- 25;

	m_bRvStatOk = m_StatBar.Create(WS_CHILD | WS_BORDER | WS_VISIBLE ,rect,this,
        				        IDC_STATUSBAR);

    	if (m_bRvStatOk == NULL)
	{
         		AfxMessageBox ("Status Bar not created!", NULL, MB_OK );
	}

	//
   	//	get size of window, use to configure the status
    	//	bar with four separate parts
    	//
    
	CRect rWin;
   	this->GetWindowRect(&rWin);
   	nTotWide = rWin.right-rWin.left;

	//
	// Make each part 1/4 of the total width of the window.
	//
   
	m_Widths[0] = nTotWide / 4;
   	m_Widths[1] = nTotWide / 2;
   	m_Widths[2] = nTotWide - m_Widths[0];
   	m_Widths[3] = -1;

	m_StatBar.SetMinHeight(25);
	m_StatBar.SetParts( 4, m_Widths);

	//
	// now lets put some text, different styles into parts of status bar
	//

	m_StatBar.SetText("WITH BORDER.", 0,0);
	m_StatBar.SetText("WITHOUT BORDER.",1,SBT_NOBORDERS);
	m_StatBar.SetText("POPUP.",2,SBT_POPOUT);

 	//
	//	make the last part owner-drawn, add a bitmap
	//

	m_StatBar.SetText(NULL,3, SBT_OWNERDRAW);

	//	hBmp is a Global Variable of type HBITMAP 
	hBmp = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));

/************************************************************************/
/*		End STATUSBAR													*/
/************************************************************************/

	// TODO: Add extra initialization here

	return TRUE;  // return TRUE  unless you set the focus to a control

}

The fourth pane of the status bar is owner drawn because it is used to display
a bitmap. In order to do this, simply add a message handler for the dialog’s
WM_DRAWITEM message. Once you’ve added that function, update it so that when finished
it looks like the following.


void CMyDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{

	//
	// Draw bitmap in status bar
	//

	HDC hdcMem;		// device context for memory
    	HGDIOBJ hbmOld; 		// old bitmap area we're over-writing
    	BITMAP bm;		// bitmap we're using

	//
    	// Create a compatible DC in memory
	//

	hdcMem = CreateCompatibleDC(lpDrawItemStruct->hDC);
    	// Select the "logo.bmp" bitmap into the DC.
    	hbmOld = ::SelectObject(hdcMem, hBmp);
    	// Get the size of the bitmap
    	::GetObject(hBmp, sizeof(bm), &bm);
    	// Blt the bitmap to the part.

    	BitBlt(lpDrawItemStruct->hDC,lpDrawItemStruct->rcItem.left,
    	lpDrawItemStruct->rcItem.top, bm.bmWidth, bm.bmHeight,
        	hdcMem, 0, 0,SRCCOPY);


	//
	// Add some text..1st. get bounding rectangle, then position & display text
	//

	char szText[16];
	RECT rText;  // text rectangle
	rText.left = lpDrawItemStruct->rcItem.left+24;
	rText.top  = lpDrawItemStruct->rcItem.top;
	rText.right = lpDrawItemStruct->rcItem.right-20;
	rText.bottom = lpDrawItemStruct->rcItem.bottom;

    	//
    	//  add some text after the logo bitmap here
    	//

	memset(szText,0,sizeof(szText));
	strcpy(szText,"LOGO");		// text to draw

	SelectObject( lpDrawItemStruct->hDC, GetStockObject( ANSI_VAR_FONT ) );
	::SetBkColor(lpDrawItemStruct->hDC, 0x00c0c0c0);  // set background color
    	ExtTextOut(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.left+24, lpDrawItemStruct->rcItem.top+4, ETO_OPAQUE, &rText, szText,
    	strlen(szText),NULL );		// draw the text in the rectangle rText

	//
	// End adding text.  Reselect the original object into the DC.
	//

    	SelectObject(hdcMem, hbmOld);
    	// Delete the compatible DC. 
    	DeleteDC(hdcMem);
}

Make the following changes to the dialog’s header file.


class CMyDlg : public CDialog
{

// Construction
public:
	CMyDlg(CWnd* pParent = NULL);	// standard constructor
	CStatusBarCtrl	m_StatBar;

	.....................................
	...................................
	......................................
}

Finally, make the following changes to the resource.h file.


//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
//

#define IDM_ABOUTBOX		0x0010
#define IDC_STATUSBAR           32500
	.....................................
	...................................
	......................................

That’s it! You now have a status bar at the bottom of your dialog!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read