我们经常看到 有些控件式放到工具栏上,但是我用微软工具栏的编辑器去编辑的时候发现根本完成不了这样任务。对于这样的需求,我们应该怎么样去解决呢?方法也很简单,就是要改造工具栏,从已有的工具栏上去派生出一个新的工具栏,派生新的工具栏的时候将你的需要添加控件的对象加入。frame 创建工具栏的时候,首先为你要新创建的控件占个位置,这个位置的获取是通过分割符来获取的,你先
void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
设置成 分割符格式,
需要注意的是,当给出的nStyle是TBBS_SEPARATOR的时候,iImage是指它的宽度,而不是图片的编号。这个功能在向工具条中添加其它控件(比如编辑控件、组合框控件)的时候非常有用,它可以改变按钮的位置,为添加的控件留出空间。
另外值得你注意的是:
用于改变工具条中按钮的样式: m_wndToolBar.SetButtonInfo(i, ID_FILE_SAVE, TBBS_CHECKBOX, 2);该代码将工具条按钮ID_FILE_SAVE设置成CHECKBOX按钮,即单击该按钮显示按下,再次单击显示抬起。
你同时对这个控件进行实例化的create,创建这个控件的时候要知道他的ID,你可以自己去找一个系统没用的ID补上。并将这个控件移到这个按钮上来。用getitemrect 去获取窗口的矩形,用movewindow 去移动窗口到你指定工具栏上。这样就大功告成了。如果在这个工具栏上放上多个控件,方法也是这样。但是需要注意的事,你要将getitemrect 的rect进行分割。然后将控件依次移到相应的rect上。这样多个控件就在同一个工具栏上。
加好控件的下一步,就是要如何去加载消息的响应函数了。这个也是要手动去添加,方法和加动态按钮的方法类似。一 在点h文件中加消息相应函数声明,在cpp文件加消息相应函数,在BEGINMESSAGE 和ENDMESSAGE宏当中去添加消息相应的宏 。
这样一个在工具栏上添加控件的过程就这样完成了 。大家可以去试试。我添加测试过。也可以参考http://www.codeproject.com/Articles/2726/Toolbars-with-embedded-Combo-Boxes
class CToolBarWithCombo : public CToolBar { public: CComboBox m_comboBox; // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CToolBarWithCombo) //}}AFX_VIRTUAL BOOL CreateComboBox(class CComboBox& comboBox, UINT nIndex, UINT nID, int nWidth, int nDropHeight); // Generated message map functions protected: //{{AFX_MSG(CToolBarWithCombo) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; BOOL CToolBarWithCombo::CreateComboBox(CComboBox& comboBox, UINT nIndex, UINT nID, int nWidth, int nDropHeight) { // Create the combo box SetButtonInfo(nIndex, nID, TBBS_SEPARATOR, nWidth); CRect rect; GetItemRect(nIndex, &rect); rect.top = 1; rect.bottom = rect.top + nDropHeight; if (!comboBox.Create(CBS_DROPDOWN|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL, rect, this, nID)) { TRACE("Failed to create combo-box\n"); return FALSE; } return TRUE; }
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } // Combo box is assigned index of 3, this means it will be placed after the // third button in a toolbar if (!m_wndToolBar.CreateComboBox(m_wndToolBar.m_comboBox, 3, ID_COMBO, 150, 100)) { TRACE0("Failed to create toolbar's combo box\n"); return -1; // fail to create }
class CSmartComboBox : public CComboBox { protected: CFont m_font; public: CSmartComboBox(); LONG m_lfHeight; LONG m_lfWeight; CString m_strFaceName; BOOL CreateFont(LONG lfHeight, LONG lfWeight, LPCTSTR lpszFaceName); // Generated message map functions protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() }; CSmartComboBox::CSmartComboBox() { m_lfHeight = -10; m_lfWeight = FW_NORMAL; m_strFaceName = _T("MS Sans Serif"); m_nMaxStrings = 10; } BEGIN_MESSAGE_MAP(CSmartComboBox, CComboBox) ON_WM_CREATE() END_MESSAGE_MAP() int CSmartComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CComboBox::OnCreate(lpCreateStruct) == -1) return -1; if( !CreateFont(m_lfHeight, m_lfWeight, m_strFaceName) ) { TRACE0("Failed to create font for combo box\n"); return -1; // fail to create } return 0; } BOOL CSmartComboBox::CreateFont(LONG lfHeight, LONG lfWeight, LPCTSTR lpszFaceName) { // Create a font for the combobox LOGFONT logFont; memset(&logFont, 0, sizeof(logFont)); if (!::GetSystemMetrics(SM_DBCSENABLED)) { // Since design guide says toolbars are fixed height so is the font. logFont.lfHeight = lfHeight; logFont.lfWeight = lfWeight; CString strDefaultFont = lpszFaceName; lstrcpy(logFont.lfFaceName, strDefaultFont); if (!m_font.CreateFontIndirect(&logFont)) { TRACE("Could Not create font for combo\n"); return FALSE; } SetFont(&m_font); } else { m_font.Attach(::GetStockObject(SYSTEM_FONT)); SetFont(&m_font); } return TRUE; }
Adding response to user commands
Once combo box is embedded into a toolbar, its properties can be accessed in a traditional manner. But in order to provide prompt response to user commands, embedded combo boxes need to cooperate with their container, i.e. the toolbar. Then, the user will be able to type some text into a combo box, press "Enter", and the corresponding command is sent to an application.
We will demonstrate this step with an application that has two combo boxes embedded in a toolbar. This is important to verify that the command is fetched by the right combo box.
class CToolBarWithCombo : public CToolBar { public: CSmartComboBox m_comboBox1; CSmartComboBox m_comboBox2; // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CToolBarWithCombo) virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); //}}AFX_VIRTUAL // The rest of the code is skipped } BOOL CToolBarWithCombo::OnCommand(WPARAM wParam, LPARAM lParam) { if( wParam == IDOK && lParam == 0 ) { CString strText; CString strCommand; CComboBox* rgComboBox[] = {&m_comboBox1, &m_comboBox2}; for( int index = 0; index < sizeof(rgComboBox) / sizeof(rgComboBox[0]); ++index ) { if( rgComboBox[index]->GetEditSel() != 0 ) { rgComboBox[index]->GetWindowText(strText); strCommand.Format(_T("Command from ComboBox[%d]: %s"), index+1, (LPCTSTR)strText); AfxMessageBox(strCommand); rgComboBox[index]->AddString(strText); rgComboBox[index]->SetWindowText(_T("")); } } } return CToolBar::OnCommand(wParam, lParam); }
As you can see, the trick to find which combo box has focus is to call the GetEditSel
function. Unless the cursor is placed in a combo box, the function will return 0.
Managing combo box entries
The last of our improvements is to create a combo box that will manage recent user entries. Such combo boxes are typically populated with the history of most recent search patterns, dialed phone numbers etc. They have the following common features:
- Maximum number of items is limited, once this number is reached, new entries replace oldest entries;
- Entries are added to the top of the list;
- List does not contain duplicates.
Here is the code you’ll need to add to CSmartComboBox
:
class CSmartComboBox : public CComboBox { // Only new code is shown public: int m_nMaxStrings; int AddString(LPCTSTR str); int InsertString(int index, LPCTSTR str); }; int CSmartComboBox::AddString(LPCTSTR str) { if( _tcslen(str) == 0 ) return -1; int oldIndex = FindStringExact(-1, str); if( oldIndex >= 0 ) DeleteString(oldIndex); if( GetCount() == m_nMaxStrings ) DeleteString(m_nMaxStrings-1); return CComboBox::InsertString(0, str); } int CSmartComboBox::InsertString(int index, LPCTSTR str) { if( _tcslen(str) == 0 ) return -1; int oldIndex = FindStringExact(-1, str); if( oldIndex >= 0 ) { DeleteString(oldIndex); if( index >= oldIndex ) --index; } if( GetCount() == m_nMaxStrings ) DeleteString(m_nMaxStrings-1); return CComboBox::InsertString(index, str); }
The sample project that follows this article contains source code and a test application that demonstrates embedded combo boxes.