Example: Control in the toolbar

Step 1:

new a project with SDI, compile and run

Step 2:

Add a placeholder in the toolbar icon editor, make it the 4-th icon, change the Promp as 選取項目並顯示\n選取, also add a separator after it

(Keys: 1. drag and drop, 2. you need to give it an ID, ex. IDM_TOOLCOMBO, otherwise the editor would remove the change next time you open the toolbar in the resource editor)

Step 3:

In the class viewer, add a new class CComboToolBar, derived from the MFC class CToolBar.

The object corresponding to this new class is to replace the original toolbar in the main frame window CMainFrame::m_wndToolBar (see Step 4)

Step 4:

In the class viewer, find the new class CComboToolBar and add a public member variable m_combobox of type CComboBox

In the class viewer, find the class CMainFrame. Open its class definition file (MainFrm.h). Replace the line CToolBar m_wndToolBar; by CComboToolBar m_wndToolBar;

You should be able to compile and run this project now. (You might have to add some #include statement before the added line can be compiled successfully.)

Step 5:

CRect rect;
m_wndToolBar.SetButtonInfo (5,IDM_TOOLCOMBO,TBBS_SEPARATOR,60);//設置下拉式列示方塊的寬度
m_wndToolBar.GetItemRect (5,&rect);//得到下拉式列示方塊位置

rect.bottom +=100;//設置下拉式列示方塊高度

//建立下拉式列示方塊
if(!m_wndToolBar.m_combobox.Create (CBS_DROPDOWN|WS_VISIBLE|
WS_TABSTOP|CBS_AUTOHSCROLL,rect, &m_wndToolBar,IDM_TOOLCOMBO)) return -1; // 在下拉式列示方塊中加入字串 m_wndToolBar.m_combobox.AddString ("北京");
m_wndToolBar.m_combobox.AddString ("天津");
m_wndToolBar.m_combobox.AddString ("上海");

compile and run the project, you will find the combo box in your toolbar, the three entries are as added. You can select any one of them.

Step 6:

A user can select anyone item in the combo box at any time. Assume that we need to read the selection in and draw the corresponding map in the client area. How do you obtain the current selected information?

Look into MSDN Library and search the method of CComboBox. You can find an interface function call CComboBox::GetCurSel(). This function does not need any input and returns an index to the current selection item (0-based index).

Now in the OnDraw(CDC *pDC) member function of your view class, you need to

  1. obtain the pointer of the m_combobox windows, which is a public memeber of CComboToolbar class and use GetCurSel() to retrieve the current selection as follows
    CComboBox *combobox = ((CMainFrame *)AfxGetMainWnd())->GetCombobox();
    int idSelected = combobox->GetCurSel();
    int nCount = combobox->GetCount();
    if ((idSelected != LB_ERR) && (nCount > 0)) 
    // LB_ERR: no item is selected
    {
        if (idSelected < nCount)
        {
            CString str;
            str.Format("%d", idSelected);
            pDC->TextOut(100, 100, str);
        }
    }
  2. m_combobox is a public data member of the object m_wndToolBar and m_wndToolBar is a protected member of CMainFrame class. You need to add an interface function CMainFrame::GetCombobox() to CMainFrame in order to retrieve the pointer of m_combobox
  3. Now you can compile the program and run it. You might find that it does not show anything at first because without any selection, GetCurSel() would return CB_ERR. If you select some item in the dropdown list. You might not see the change unless you minimize the window and reshow it to force it repaint its content.

    The problem seems to be that your program is not notified when the user change something in the combobox. Let's try fix this at the next step.

Step 7:

At the time a combobox is manipulated by the user, the main window gets some WM_COMMAND messages with notification being CBN_SELCHANGE, CBN_SELENDOK, CBN_SELENDCANCEL, CBN_EDITCHANGE, CBN_DROPDOWN, CBN_CLOSEUP...and control ID being IDM_TOOLCOMBO as we used in the Create() function (Look up "Message Maps" in MSDN Library)

In the class CMainFrame, find the message map and add the following to capture the special WM_COMMAND message from the control item

    ON_CBN_SELENDOK(IDM_TOOLCOMBO, OnSelEndOK)
  
In CMainFrame.h add the following function header after DECLARE_MESSAGE_MAP()
    public:
        afx_msg void OnSelEndOK();
  
In CMainFrame.cpp add the following function definition to force the mainframe and the view redrawing itself
    void CMainFrame::OnSelEndOK()
    {
        // TODO: 在此加入您的命令處理常式程式碼
        Invalidate();
    }
  

Compile and test your results