
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