
Introduction
This article shows a simple way to add buttons to a toolbar and set the image, tooltip and status bar text dynamically.
Strategy
Override CToolBar::OnNotify to set dynamic tooltips and CMainFrame::GetMessageString to provide dynamic status text. Create a bitmap and draw the buttons onto it. Use the SetBitmap toolbar method to assign the bitmap to the toolbar control. Insert and set the button information with the SetButtons and SetButtonInfo methods. Then create the MFC Application Project and add a CMyDynamicToolBar CToolBar derived class:
- File -> New -> New project. Create a new
DynamicToolBar Visual C++, MFC application.
-
In the class view, right click the DynamicToolBar project. Add->Add Class... Select an MFC class on the right pane and click Open.
- Select
CToolBar from the Base class drop-down list. Type CMyDynamicToolBar into the Class Name edit box.
- Click Finish.
We need to store the tooltip and status texts. For this example, we will use the same text vector array. Add the following code to the MyDynamicToolBar.h file:
#pragma once
typedef std::vector <CString> V_CString;
- Right click the
CMyDynamicToolBar class in Class view -> Add-> Add Variable...
- From the Access drop down list, select
private.
- Into the Variable Type edit box, type
V_CString and into the Variable Name edit box, type m_asToolTips.
- Into the Comment edit box, type
Variable for storing tool tip text.
Now we will override the CToolBar::OnNotify event for responding to the TTN_NEEDTEXT message of the tool bar.
- Right click the
CMyDynamicToolBar class in Class view -> Properties.
- On Properties, click the Override button.
- Scroll down to the
OnNotify event and click on the cell right next to it.
- Select <Add> OnNotify from the drop-down list.
- Press Ctrl+Shift+Enter to change to full screen view.
- Replace
CMyDynamicToolBar::OnNotify with:
BOOL CMyDynamicToolBar::OnNotify(WPARAM wParam,
LPARAM lParam, LRESULT* pResult)
{
LPNMHDR pNMHDR = ((LPNMHDR)lParam);
TOOLTIPTEXTW *pTTT=(TOOLTIPTEXTW *)pNMHDR;
UINT t = TTN_NEEDTEXTW;
if(pNMHDR->code == t)
{
UINT nID=pNMHDR->idFrom;
if(!(pTTT->uFlags & TTF_IDISHWND))
{
if ((nID >= ID_MYTOOLBAR_BUTTON1) ||
(nID <= ID_MYTOOLBAR_BUTTONLAST))
{
USES_CONVERSION;
UINT btn1 = ID_MYTOOLBAR_BUTTON1;
pTTT->lpszText = T2W(m_aCString[nID - btn1]);
pTTT->hinst = NULL;
return TRUE;
}
}
}
return CToolBar::OnNotify(wParam, lParam, pResult);
}
Press Ctrl+Shift+Enter to change back from full screen view. Add the following to the end of the stdafx.h file:
#define ID_MYTOOLBAR_BUTTON1 WM_USER + 1
#define ID_MYTOOLBAR_BUTTONLAST WM_USER + 100
Now we will add some methods for setting and retrieving the tooltips. For simplicity's sake, we will assume that all insertions are consecutive, in the same order for button IDs.
- Right click the
CMyDynamicToolBar class in Class view -> Add -> Add Function...
- Set the Return type to
void and set the Function name to InsertToolTip.
- Also set the parameter type to
CString and the parameter name to sToolTip.
- Next, click the Add button.
- Set the comment to
Inserts tooltip text consecutively.
- Click Finish.
- Edit
CMyDynamicToolBar::InsertToolTip into this:
void CMyDynamicToolBar::InsertToolTip(CString sToolTip)
{
m_asToolTips.push_back(sToolTip);
}
Repeat the above steps to create the following CMyDynamicToolBar::GetToolTip function.
CString CMyDynamicToolBar::GetToolTip(UINT nID)
{
UINT btn1 = ID_MYTOOLBAR_BUTTON1;
return m_asToolTips[nID - btn1];
}
Now modify CMyDynamicToolBar::~CMyDynamicToolBar() to clear the ToolTips arrays on destruction.
CMyDynamicToolBar::~CMyDynamicToolBar()
{
m_asToolTips.clear();
}
Now add code for handling the creation of CMyDynamicToolBar on the main frame window:
- Right click CMainFrame class. -> Add Variable...
- Type
CMyDynamicToolBar into the Variable Type edit box.
- Type
m_wndMyToolBar into the Variable Name edit box.
- Click Finish.
- Double click
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
Then add the following code:
if (!m_wndMyToolBar.CreateEx(this,
TBSTYLE_FLAT , WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC))
{
TRACE0("Failed to create dynamic toolbar\n");
return -1; }
CDC *dc = this->GetDC();
CDC dcMem;
dcMem.CreateCompatibleDC(dc);
HBITMAP hbitmap = CreateCompatibleBitmap(dc->m_hDC, 50*16, 16);
CBitmap *bmp = CBitmap::FromHandle(hbitmap);
CBitmap* pOldBitmap = dcMem.SelectObject( bmp );
CRect rect(0, 0, 5*16, 16);
FillRect(dcMem.m_hDC, &rect, (HBRUSH) (COLOR_WINDOW));
dcMem.SetMapMode(MM_TEXT);
CString tmp = "Button ";
for (int i=0;i < 5;i++)
{
HICON icon = LoadIcon(NULL,MAKEINTRESOURCE(32512+i));
dcMem.DrawIcon( i*16, 0, icon );
char buffer[2];
m_wndMyToolBar.InsertToolTip( tmp + itoa(i,buffer,10));
}
dcMem.SelectObject(pOldBitmap);
dcMem.DeleteDC();
pOldBitmap->DeleteObject();
m_wndMyToolBar.SetBitmap(hbitmap);
m_wndMyToolBar.SetButtons(NULL,i);
for(int j=0; j < i; j++)
{
m_wndMyToolBar.SetButtonInfo(j, ID_MYTOOLBAR_BUTTON1 + j,
TBBS_BUTTON | TBBS_AUTOSIZE, j);
}
So far, we have the toolbar created and it shows tooltip text, but we also want to have the same text on the status bar. We therefore need to override the CMainFrame::GetMessageString method that is responsible for providing status bar text according to control IDs:
- Right click the
CMainFrame class in Class view -> Properties.
- On Properties, click the Override button.
- Scroll down to the
GetMessageString method.
- Click on the cell right next to it and select <Add> GetMessageString from the drop down list.
- Replace
MainFrame::GetMessageString with:
void CMainFrame::GetMessageString(UINT nID, CString& rMessage) const
{
if ((nID >= ID_MYTOOLBAR_BUTTON1) && (nID <= ID_MYTOOLBAR_BUTTONLAST))
rMessage = (const_cast <CMyDynamicToolBar*> (&m_wndMyToolBar))
->GetToolTip(nID);
else
CMDIFrameWnd::GetMessageString(nID, rMessage);
return;
}
Build and run the application. (F7) (F5)
Points of interest
MSDN documents state that we need to process the TBN_GETINFOTIP message for specifying the tooltip text. A simpler way to get tooltip texts is to set the TBSTYLE_LIST style and the TBSTYLE_EX_MIXEDBUTTONS toolbar extended style. For buttons that do not have the BTNS_SHOWTEXT style, the toolbar control will automatically display the button text as a tooltip. This works for Version 5.81 of Common Controls.
History
- 18 July, 2007 -- Original version posted
- 24 July, 2007 -- Updated