Click here to Skip to main content
15,881,719 members
Articles / Desktop Programming / MFC

Balloon Help as a non-modal replacement for MessageBox()

Rate me:
Please Sign up or sign in to vote.
4.98/5 (62 votes)
7 Aug 2002CPOL13 min read 1M   12.3K   228  
Although sometimes useful, message boxes used to display information are often just annoying. This article describes a non-modal replacement.
#include "stdafx.h"
#include "maindlg.h"


// ctor
CMainDlg::CMainDlg():
	m_wndLButtonDown(this,1),
	m_wndMButtonDown(this,2),
	m_wndRButtonDown(this,3)
{
}
	
//
//			GetBalloonOptions
//
DWORD CMainDlg::GetBalloonOptions()
{
	DWORD dwOptions=0;
	for(int idx=0;idx<MaxOptions;++idx)
		dwOptions|=m_OptionCtrls[idx].GetOption();
	
	return dwOptions;
}

//
//			UpdateOptions
//
void CMainDlg::UpdateOptions(DWORD dwOptions)
{
	for(int idx=0;idx<MaxOptions;++idx)
		m_OptionCtrls[idx].UpdateState(dwOptions);
}

//
//			EnableOptions
//
void CMainDlg::EnableOptions(BOOL bEnable)
{
	for(int idx=0;idx<MaxOptions;++idx)
		m_OptionCtrls[idx].Enable(bEnable);
}

//
//
//
void CMainDlg::ShowBallon(HWND hWndCenter)
{
	ATLASSERT(::IsWindow(hWndCenter));

	//
	//	title
	//
	CString strTitle;

	const int ccTitle=m_edtTitle.GetWindowTextLength()+1;
	m_edtTitle.GetWindowText(strTitle.GetBuffer(ccTitle),ccTitle);
	strTitle.ReleaseBuffer();


	//
	//	content
	//
	CString strContent;

	const int ccContent=m_edtContent.GetWindowTextLength()+1;
	m_edtContent.GetWindowText(strContent.GetBuffer(ccContent),ccContent);
	strContent.ReleaseBuffer();

	//
	// timeout
	//
	BOOL bTranslated=FALSE;
	int nTimeout=GetDlgItemInt(IDC_Timeout,&bTranslated,FALSE);
	if(!bTranslated)
		nTimeout=0;


	//
	// show ballon
	//
	CBalloonHelp* pBalloon=new CBalloonHelp;
	ATLASSERT(pBalloon);

	if(m_btnUseBitmap.GetCheck())
	{
		HBITMAP hBmp=LoadBitmap(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDB_Bob));
		pBalloon->SetIcon(hBmp, RGB(255,255,255)); // bitmap, transparent color
	}
	else
	{
		//pBalloon->SetIcon(IDI_INFORMATION);

		// use the cool WTL Icon (thanks, Josh!!) with a size of 32x32, so everyone can see it :-)
		pBalloon->SetIcon(LoadIcon(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDR_MAINFRAME)));
	}

	if(m_btnFollowMe.GetCheck())
	{
		pBalloon->SetFollowMe(hWndCenter,NULL);// follow center point
	}
	else
	{
		pBalloon->SetAnchorPoint(hWndCenter);
	}
	
	// gray balloon
	//pBalloon->SetBackgroundColor(CBalloonHelp::OleSysColorBits|COLOR_BTNFACE);
	//pBalloon->SetForeGroundColor(CBalloonHelp::OleSysColorBits|COLOR_BTNTEXT);

	// codeproject orange...
	//pBalloon->SetBackgroundColor(RGB(255,153,0));
	//pBalloon->SetForeGroundColor(RGB(0,0,0));
	
	pBalloon->Create(
		m_hWnd,
		strTitle,
		strContent,
		NULL,	// dont't override existing anchor point
		GetBalloonOptions()|CBalloonHelp::BODeleteThisOnClose, // delete pBalloon on close
		NULL,
		nTimeout);

	
}


//
//			OnInitDialog
//
BOOL CMainDlg::OnInitDialog(HWND, LPARAM)
{
	// center the dialog on the screen
	CenterWindow();

	// set icons
	HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
		IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
	SetIcon(hIcon, TRUE);
	HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
		IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
	SetIcon(hIconSmall, FALSE);

	
	m_OptionCtrls[ 0].Init(GetDlgItem(IDC_BOShowCloseButton),		CBalloonHelp::BOShowCloseButton);
	m_OptionCtrls[ 1].Init(GetDlgItem(IDC_BOShowInnerShadow),		CBalloonHelp::BOShowInnerShadow);
	m_OptionCtrls[ 2].Init(GetDlgItem(IDC_BOShowTopMost),			CBalloonHelp::BOShowTopMost);

	m_OptionCtrls[ 3].Init(GetDlgItem(IDC_BOCloseOnLButtonDown),	CBalloonHelp::BOCloseOnLButtonDown);
	m_OptionCtrls[ 4].Init(GetDlgItem(IDC_BOCloseOnMButtonDown),	CBalloonHelp::BOCloseOnMButtonDown);
	m_OptionCtrls[ 5].Init(GetDlgItem(IDC_BOCloseOnRButtonDown),	CBalloonHelp::BOCloseOnRButtonDown);

	m_OptionCtrls[ 6].Init(GetDlgItem(IDC_BOCloseOnLButtonUp),		CBalloonHelp::BOCloseOnLButtonUp);
	m_OptionCtrls[ 7].Init(GetDlgItem(IDC_BOCloseOnMButtonUp),		CBalloonHelp::BOCloseOnMButtonUp);
	m_OptionCtrls[ 8].Init(GetDlgItem(IDC_BOCloseOnRButtonUp),		CBalloonHelp::BOCloseOnRButtonUp);

	m_OptionCtrls[ 9].Init(GetDlgItem(IDC_BOCloseOnMouseMove),		CBalloonHelp::BOCloseOnMouseMove);
	m_OptionCtrls[10].Init(GetDlgItem(IDC_BOCloseOnKeyDown),		CBalloonHelp::BOCloseOnKeyDown);
	m_OptionCtrls[11].Init(GetDlgItem(IDC_BOCloseOnAppDeactivate),	CBalloonHelp::BOCloseOnAppDeactivate);

	m_OptionCtrls[12].Init(GetDlgItem(IDC_BODisableFadeIn),			CBalloonHelp::BODisableFadeIn);
	m_OptionCtrls[13].Init(GetDlgItem(IDC_BODisableFadeOut),		CBalloonHelp::BODisableFadeOut);

	m_btnBoDefault=GetDlgItem(IDC_BODefault);
	ATLASSERT(m_btnBoDefault.IsWindow());

	m_btnUseBitmap=GetDlgItem(IDC_UseBitmap);
	ATLASSERT(m_btnUseBitmap.IsWindow());
	m_btnUseBitmap.SetCheck(1);

	m_btnFollowMe=GetDlgItem(IDC_FollowMe);
	ATLASSERT(m_btnFollowMe.IsWindow());

	m_edtTitle=GetDlgItem(IDC_Title);
	ATLASSERT(m_edtTitle.IsWindow());
	m_edtTitle.SetWindowText(_T("<<title goes here>>"));
	
	m_edtContent=GetDlgItem(IDC_Content);
	ATLASSERT(m_edtContent.IsWindow());
	m_edtContent.SetWindowText(_T("<<content goes here>>"));

	UpdateOptions(CBalloonHelp::BODefault);

	m_wndLButtonDown.SubclassWindow(GetDlgItem(IDC_LButtonDown));
	m_wndMButtonDown.SubclassWindow(GetDlgItem(IDC_MButtonDown));
	m_wndRButtonDown.SubclassWindow(GetDlgItem(IDC_RButtonDown));

	//
	//	create and show welcome ballon
	//
	m_wndBalloon.SetIcon(LoadBitmap(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDB_Bob)),RGB(255,255,255));
   
	CFontHandle FontTitle; // deleted by balloon.
	FontTitle.CreatePointFont(120, _T("Comic Sans MS"));
	m_wndBalloon.SetTitleFont(FontTitle); 
	
	CFontHandle FontContent; // deleted by balloon.
	FontContent.CreatePointFont(100, _T("Comic Sans MS"));
	m_wndBalloon.SetContentFont(FontContent); 

	CRect rcClient;
	GetClientRect(rcClient);
	ClientToScreen(rcClient);

	m_wndBalloon.SetFollowMe(m_hWnd, &rcClient.BottomRight());

	m_wndBalloon.Create(
		m_hWnd,
		_T("Hello!"), 
		_T("Welcome to the Balloon Help test app!"), 
		NULL, // already set by SetFollowMe()
		CBalloonHelp::BOShowInnerShadow|CBalloonHelp::BOShowCloseButton,
		NULL,
		10000
		);

	return TRUE;

}// OnInitDialog

//
//			OnBoDefault
//
void CMainDlg::OnBoDefaultClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	if(m_btnBoDefault.GetCheck())
	{
		UpdateOptions(CBalloonHelp::BODefault);
		EnableOptions(FALSE);
	}
	else
	{
		EnableOptions(TRUE);
	}
}

//
//
//
void CMainDlg::OnHelp(LPHELPINFO pHelpInfo)
{
	if(NULL==pHelpInfo->hItemHandle || HELPINFO_WINDOW!=pHelpInfo->iContextType)
		return;

	const HWND hWndControl=(HWND)pHelpInfo->hItemHandle;
	
	CString strTitle;
	CString strMsg;
	switch(pHelpInfo->iCtrlId)
	{
	case IDOK:
		strTitle= _T("Close");
		strMsg	= _T("Click this button to close the program.");
		break;
	case IDC_BOCloseOnLButtonDown:
		strTitle= _T("BOCloseOnLButtonDown");
		strMsg	= _T("Closes window on WM_LBUTTONDOWN.");
		break;
	case IDC_BOCloseOnMButtonDown:
		strTitle= _T("BOCloseOnMButtonDown");
		strMsg	= _T("Closes window on WM_MBUTTONDOWN.");
		break;
	case IDC_BOCloseOnRButtonDown:
		strTitle= _T("BOCloseOnRButtonDown");
		strMsg	= _T("Closes window on WM_RBUTTONDOWN.");
		break;
	case IDC_BOCloseOnLButtonUp:
		strTitle= _T("BOCloseOnLButtonUp");
		strMsg	= _T("Closes window on WM_LBUTTONUP.");
		break;
	case IDC_BOCloseOnMButtonUp:
		strTitle= _T("BOCloseOnMButtonUp");
		strMsg	= _T("closes window on WM_MBUTTONUP.");
		break;
	case IDC_BOCloseOnRButtonUp:
		strTitle= _T("BOCloseOnRButtonUp");
		strMsg	= _T("Closes window on WM_RBUTTON_UP.");
		break;
	case IDC_BOCloseOnMouseMove:
		strTitle= _T("BOCloseOnMouseMove");
		strMsg	= _T("Closes window when user moves mouse past threshhold.");
		break;
	case IDC_BOCloseOnKeyDown:
		strTitle= _T("BOCloseOnKeyDown");
		strMsg	= _T("Closes window on the next keypress message sent to this thread.");
		break;
	case IDC_BOCloseOnAppDeactivate:
		strTitle= _T("BOCloseOnAppDeactivate");
		strMsg	= _T("Closes window when the application is being deactivated.");
		break;
	case IDC_BOShowCloseButton:
		strTitle= _T("BOShowCloseButton");
		strMsg	= _T("Shows close button in upper right.");
		break;
	case IDC_BOShowInnerShadow:
		strTitle= _T("BOShowInnerShadow");
		strMsg	= _T("Draw inner shadow in balloon.");
		break;
	case IDC_BOShowTopMost:
		strTitle= _T("BOShowTopMost");
		strMsg	= _T("Place balloon above all other windows.");
		break;
	case IDC_BODisableFadeIn:
		strTitle= _T("BODisableFadeIn");
		strMsg	= _T("Disable the fade-in effect (overrides system and user settings).");
		break;
	case IDC_BODisableFadeOut:
		strTitle= _T("BODisableFadeOut");
		strMsg	= _T("Disable the fade-out effect (overrides system and user settings).");
		break;
	case IDC_BODefault:
		strTitle= _T("BODefault");
		strMsg	= _T("Apply default options.");
		break;
	case IDC_Title:
		strTitle= _T("Title");
		strMsg	= _T("The title of the balloon.");
		break;
	case IDC_Content:
		strTitle= _T("Content");
		strMsg	= _T("The Content of the balloon.");
		break;
	case IDC_UseBitmap:
		strTitle= _T("Use Bitmap");
		strMsg	= _T("Use \"Bob\" as the balloon's icon.");
		break;
	case IDC_Timeout:
		strTitle= _T("Timeout");
		strMsg	= _T("Number of milliseconds the balloon remains open.  Set to 0 to disable timeout.");
		break;
	case IDC_LButtonDown:
		strTitle= _T("Feedback balloon launcher area");
		strMsg	= _T("Press the left mouse button here.");
		break;
	case IDC_MButtonDown:
		strTitle= _T("Feedback balloon launcher area");
		strMsg	= _T("Press the middle mouse button here.");
		break;
	case IDC_RButtonDown:
		strTitle= _T("Feedback balloon launcher area");
		strMsg	= _T("Press the right mouse button here.");
		break;
	default:
		return;
	}

	CBalloonHelp::Show(
		m_hWnd,			// owner window
		strTitle,		// title of balloon
		strMsg,			// content of balloon
		hWndControl,	// center "anchor" to this control
		IDI_INFORMATION,	// show info icon
		CBalloonHelp::BOCloseOnKeyDown|CBalloonHelp::BOCloseOnMouseMove|CBalloonHelp::BOCloseOnAppDeactivate|CBalloonHelp::BOCloseOnButtonDown
		);
}



// eof

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Poke...

Comments and Discussions