分类: C/C++
2008-08-30 14:17:06
This article shows a simple way to add buttons to a toolbar and set the image, tooltip and status bar text dynamically.
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:
DynamicToolBar
Visual C++, MFC application.
DynamicToolBar
project. Add->Add Class... Select an MFC class on the right pane and click Open. CToolBar
from the Base class drop-down list. Type CMyDynamicToolBar
into the Class Name edit box.
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;
CMyDynamicToolBar
class in Class view -> Add-> Add Variable...
private
.
V_CString
and into the Variable Name edit box, type m_asToolTips
.
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.
CMyDynamicToolBar
class in Class view -> Properties.
OnNotify
event and click on the cell right next to it.
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.
CMyDynamicToolBar
class in Class view -> Add -> Add Function...
void
and set the Function name to InsertToolTip
.
CString
and the parameter name to sToolTip
.
Inserts tooltip text consecutively
.
CMyDynamicToolBar::InsertToolTip
into this: // Inserts tool tips text consecutively
void CMyDynamicToolBar::InsertToolTip(CString sToolTip)
{
m_asToolTips.push_back(sToolTip);
}
Repeat the above steps to create the following CMyDynamicToolBar::GetToolTip
function.
// Get tool tips text
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.
// Clear tool tips text array
CMyDynamicToolBar::~CMyDynamicToolBar()
{
m_asToolTips.clear();
}
Now add code for handling the creation of CMyDynamicToolBar
on the main frame window:
CMyDynamicToolBar
into the Variable Type edit box.
m_wndMyToolBar
into the Variable Name edit box.
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
Then add the following code:
// begin create dynamic tool bar
if (!m_wndMyToolBar.CreateEx(this,
TBSTYLE_FLAT /*| TBSTYLE_TRANSPARENT*/, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC))
{
TRACE0("Failed to create dynamic toolbar\n");
return -1; // fail to create
}
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 );
//draw a filled rectangle with the background (window) color
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);
}
// end create dynamic tool bar
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:
CMainFrame
class in Class view -> Properties.
GetMessageString
method.
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)
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.