Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5873141
  • 博文数量: 671
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 7310
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-14 09:56
文章分类

全部博文(671)

文章存档

2011年(1)

2010年(2)

2009年(24)

2008年(271)

2007年(319)

2006年(54)

我的朋友

分类: C/C++

2008-08-30 14:17:06

Screenshot - DynamicToolBar.gif

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:

  1. File -> New -> New project. Create a new DynamicToolBar Visual C++, MFC application.
  2. In the class view, right click the DynamicToolBar project. Add->Add Class... Select an MFC class on the right pane and click Open.
  3. Select CToolBar from the Base class drop-down list. Type CMyDynamicToolBar into the Class Name edit box.
  4. 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;
  1. Right click the CMyDynamicToolBar class in Class view -> Add-> Add Variable...
  2. From the Access drop down list, select private.
  3. Into the Variable Type edit box, type V_CString and into the Variable Name edit box, type m_asToolTips.
  4. 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.

  1. Right click the CMyDynamicToolBar class in Class view -> Properties.
  2. On Properties, click the Override button.
  3. Scroll down to the OnNotify event and click on the cell right next to it.
  4. Select OnNotify from the drop-down list.
  5. Press Ctrl+Shift+Enter to change to full screen view.
  6. 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.

  1. Right click the CMyDynamicToolBar class in Class view -> Add -> Add Function...
  2. Set the Return type to void and set the Function name to InsertToolTip.
  3. Also set the parameter type to CString and the parameter name to sToolTip.
  4. Next, click the Add button.
  5. Set the comment to Inserts tooltip text consecutively.
  6. Click Finish.
  7. Edit 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:

  1. Right click CMainFrame class. -> Add Variable...
  2. Type CMyDynamicToolBar into the Variable Type edit box.
  3. Type m_wndMyToolBar into the Variable Name edit box.
  4. Click Finish.
  5. Double click CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

Then add the following code:

Collapse
// 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:

  1. Right click the CMainFrame class in Class view -> Properties.
  2. On Properties, click the Override button.
  3. Scroll down to the GetMessageString method.
  4. Click on the cell right next to it and select GetMessageString from the drop down list.
  5. 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found

阅读(1274) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~