介绍 一个组合框,具
有自动完成功能,也允许多个 列。它来源于Chris Maunder的CComboCompletion。 版本1.2修复了以下问题: 尺寸问题,由马格努斯·埃格伯格和他的同事提供 AddRow()例程现在被重载,以便更容易添加 行。不再需要SetColCount(UINT)。的重载 一个CComboBox例程,已被DeleteRow()取代。通过删除额外的特写镜头,对子字符串的奇反转也得到了解决 收到“Enter”键。 这个组合框 处理以相同字符开头且仅表示匹配的文本字符串 当它是独一无二的。即. .假设盒子里装满了字符串: 隐藏,复制Code
0 1 100 1234
在键入“1”时,这是第二个项目的唯一匹配,因此组合框 就会打开并突出那个。如果你继续“0”,那么 combobox将再次打开并显示100,但最后一个0将是 突出显示,因为这是下一个字符将去的地方。键入一个 “1”后的“2”将选择“1234”,“34”将高亮显示。多个 支持列,因此combobox必须是所有者绘制,变量,与 字符串。可以为combobox提供下拉菜单或下拉菜单的属性 列表。在后者中,输入的字符不匹配 第一列字符串将发出哔哔声并被拒绝。通过对话框中的一行创建combobox 这通常是由MS类向导为相关的类提供的 当combobox被插入对话框时: 隐藏,复制Code
class CMyDialog : CDialog { ... CAutoCombobox m_myAutoCombobox; ... }; CMyDialog::CMyDialog(...) : m_myAutoCombobox(ACB_DROP_LIST) { }
或者使用ACB_DROP_DOWN。在下面的文章中有以下内容 定义。 隐藏,复制Code
typedef vector<CString> CStringsVec; typedef vector<int> IntVec;
特殊目的成员功能如下: 隐藏,复制Code
CAutoComboBox::AddRow(const TCHAR* pString); CAutoComboBox::AddRow(const CStringsVec& allCols); CAutoCombobox::AddRow(const TCHAR* pString, CStringsVec& extraCols);
这些例程被重载以在每一行中添加字符串。第一个 如果需要单列自动补全,只需为一列添加文本。 第二个允许在向量中插入所有列的字符串 字符串。向量中的第一个字符串将被添加到实际 combobox本身和其他部分将被保存在一个内部成员字符串向量中。 第三个是向后兼容性,需要分离 字符串中的第一列用于额外的列。第一次一排 ,列的数量将被记住,而所有随后的添加必须 具有完全相同数量的列字符串。如果列为空,则使用 空字符串填充空格(_T(""))。 隐藏,复制Code
CAutoCombobox::DeleteRow(int iRow)
这将从内部删除行和相应的额外文本 向量。 隐藏,复制Code
CAutoCombobox::GetSelectedRow() const
可以通过此函数检索所选的行。如果没有行已被 唯一标识,返回值为-1。 隐藏,复制Code
CAutoCombobox::ResetSelection()
当前选择被取消,我们可以从头开始比赛 再一次 隐藏,复制Code
CAutoCombobox::ResetContent()
所有的行都从组合框和内部数组中删除,这样您就可以这样做了 重新开始填充。 隐藏,复制Code
CAutoCombobox::SetReverseEntry(bool bReverse = true)
在我的例子中,我需要允许输入来自的字符串 从右到左,而不是从左到右。对于一个数字列表,它的可变性是 通常更多的是低阶数字,所以1一般不需要输入a 许多字符得到唯一的匹配。把100写成a很奇怪 "0"后面跟着"0",然后是"1"。 隐藏,复制Code
CAutoCombobox::DeleteString(UINT uRow)
这将从内部删除行和相应的额外文本 向量。这个例程不赞成,应该由DeleteRow(int)替换。 隐藏,复制Code
CAutoCombobox::SetColCount(int iCols)
这个例程不再需要了,因此不建议使用它。列 count是从第一个AddRow(…)调用开始建立的。如果使用此例程,则必须在添加任何行之前调用,因为它有效 额外字符串向量的大小。 示例项目加载具有两列和一组数值的combobox 字符串。它是一个MDI应用程序,并已通过MS Visual Studio .NET 2003和MDI测试 Windows XP。在VS6.0实现中有一个剩下的.dsw文件 似乎也起作用了!)选择菜单项Test(^快捷方式)将打开 已被字符串填充的对话框。输入一个3将打开盒子和 显示选中“3”的行。现在继续输入453,盒子就会 再次打开,现在将选择显示为包含345337的行。指定从 这样就可以把345337保存在盒子里了。点击OK, MDI应用程序显示 通过项目:nnnn在主窗口中选择。 我需要一个不区分大小写的匹配,所以使用了CString::CompareNoCase(…)。 如果需要区分大小写的匹配,则将两个引用更改为比较 函数只需使用CString::Compare(…)。 我删除了下拉列表w的关闭母鸡的 “Enter”键出现了。这样做的目的是允许一次击键 关闭下拉列表,并触发的默认按钮 包含对话框。对话框中的组合框的正常行为是 第一个“Enter”关闭列表,第二个“Enter”触发默认值 动作,总共两个按键。如果这个额外的特写实现在a Win95/98/ME操作系统,然后一个问题出现了。有时字符串会恢复 到先前匹配的子字符串。这是由于在 ComboBox对象的Microsoft实现。没有问题 NT或XP。反转只在字符串发生的时候发生 首先匹配一个短字符串,然后匹配一个长字符串。在 在上面的列列表中,输入“1”将选择“1”行。现在进入 一个“0”,将选择“100”行。点击组合框外将关闭 下拉菜单,但是选择会因为一些未知的原因返回到“1”。 有趣的是,如果“1”后面跟着“0”来突出显示“100”和 然后向上箭头/向下箭头用于选择下一行并返回 “100”,焦点的改变将使“100”留在原位而不回调 “1”。它不会发生在选择的“3”后面跟着“2”的时候 “323513”如图所示。将焦点从选中的“323513”移开 即使列表中有一个“3”,它还是保留了这个。 记录这个的微软事件编号 错误是SRX020705601306。根据微软的说法,没有这样的工作 这就是在这个新版本中关闭的原因! 控件的主要部分在OnEditUpdate()例程中,如下所示。当一个 找到唯一匹配时,combobox将被放下,而所涉及的项目是 高亮显示。 PreTranslateMsg(…)必须测试退格或删除和取消 自动完成下一个字符。如果不这样做,这是不可能的 在系统继续输入下一个字符时纠正错误。这 在Chris Maunder的CComboCompletion示例中有更好的描述。 清单需要头文件来显示列出的变量定义 接下来,然后 下面是OnEditUpdate()代码。获取用户输入的文本行 通过GetWindowText()函数,并在找到匹配项时进行修改 SetWindowText()和SetEditSel()。 清单取自autocbox.h 隐藏,收缩,复制Code
using std::vector; typedef vector<Int> IntVec; typedef vector<CString> CStringsVec; //////////////////////////////////////////////////////////////////////// // // CAutoComboBox window // class CAutoComboBox : public CComboBox { public: // define the two types to emulate enum AutoComboBoxType { ACB_DROP_DOWN, ACB_DROP_LIST }; CAutoComboBox(AutoComboBoxType acbt = ACB_DROP_LIST); virtual ~CAutoComboBox(); // ClassWizard generated virtual function overrides private: virtual BOOL PreTranslateMessage(MSG* pMsg); virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); public: int GetSelectedRow(); int AddRow(const TCHAR* pString, const CStringsVec& extraCols); int AddRow(const CStringsVec& cols); int AddRow(const TCHAR* pString); int DeleteRow(int iRow); void SetReverseEntry(bool bReverse) { m_bReverseEntry = bReverse; } void GetLBText(int nIndex, CString& rString) const; void ResetSelection(); void ResetContent(); // the following routines are deprecated!! int DeleteString(UINT uRow); // use DeleteRow(...) void SetColCount(int iCols); // not needed any more protected: afx_msg void OnEditUpdate(); afx_msg void OnSelChange(); afx_msg void OnCbnDropdown(); DECLARE_MESSAGE_MAP() private: int FindUniqueMatchedItem(const CString& line, CString& matchedLine); int SetDroppedWidthForTextLengths(); bool LineInString(const CString& rsLine, const CString& rsString) const; int m_iSelectedRow; int m_iHorizontalExtent; // list box width for all columns bool m_bAutoComplete; // false after delete or backspace bool m_bReverseEntry; // enter characters in reverse bool m_bEditHeightSet; // true when we've set the height of the box bool m_bClosing; // stops error in selection on enter AutoComboBoxType m_autoComboBoxType; IntVec m_vecEndPixels; // ending positions for each column vector<CStringsVec> m_vecRows;// row text for each col after the first };
清单取自autocbox.cpp 隐藏,收缩,复制Code
... void CAutoComboBox::OnEditUpdate() { CString line; // partial line entered by user CString sMatchedText; // holds full line from list // get the text from the user input GetWindowText(line); int iHiLightStart = line.GetLength(); // ?? remove // TRACEFN(_T("Entering OnEditUpdate line:%s\n"), (LPCTSTR) line); // if the line is empty if(line.GetLength() == 0) { // make sure the dropdown list is closed when back to // zero characters in the edit box ShowDropDown(FALSE); // empty the selection SetWindowText(_T("")); // cancel any previous selection m_iSelectedRow = -1; // turn on autocomplete again turned off by deletes m_bAutoComplete = true; return; } // if we have seen a delete or back key we leave the text alone so // that the user can continue to go backwards to correct an entry if(!m_bAutoComplete) { // but only for one character m_bAutoComplete = true; // if reversing entry, must keep insertion point on right if(m_bReverseEntry) { SetEditSel(0, 0); } return; } // if a single match, we can display that and identify the mismatch m_iSelectedRow = FindUniqueMatchedItem(line, sMatchedText); // if we found a unique matching row if(m_iSelectedRow >= 0) { // drop down the list part of the combo box ShowDropDown(TRUE); // ?? remove // TRACE(_T("OnEditUpdate: ShowDropDown(true)\n")); // set the dropdown to show the item as well // ?? int iCurSel = SetCurSel(m_iSelectedRow); // assert(iCurSel >= 0); // we try this so that the selection occurs AFTER the dropdown // box has been filled PostMessage(CB_SETCURSEL, m_iSelectedRow, 0); // ?? remove // TRACE(_T("OnEditUpdate-Post: SetCurSel(%d)\n"), m_iSelectedRow); // now we have to also remove the selection from the edit box // since we may want to continue to add to the string and // set out own highlight on the text we have added from the match // int iStartChar = 0; int iEndChar = -1; if(!m_bReverseEntry) { // straight entry, we want to highlight the added text from // the end of the input line text to the end of the field iStartChar = line.GetLength(); } else { // reverse entry, we want to highlight the added text // on the left - from char 0 to match less line length iEndChar = sMatchedText.GetLength() - line.GetLength(); } PostMessage(CB_SETEDITSEL, 0, MAKELPARAM(iStartChar, iEndChar)); // ?? remove // TRACE(_T("OnEditUpdate-Post: SetEditSel(%d, %d)\n") // , iStartChar, iEndChar); // set the window text to the match line = sMatchedText; } // if this text won't match any string and we are emulating // a drop list so the selection is forced else if(sMatchedText.IsEmpty() && m_autoComboBoxType == ACB_DROP_LIST) { // alert the user to no match MessageBeep(MB_ICONEXCLAMATION); // if we are not entering text backwards if(!m_bReverseEntry) { // remove the last character typed in error. at the end line.Delete(line.GetLength() - 1); } else { // remove the last character typed in error (at the beginning) // which will be in the firt position line.Delete(0); } assert(iHiLightStart > 0); iHiLightStart -= 1; // restore the line since the closeup cleared the edit box SetWindowText(line); // ?? remove // TRACE(_T("OnEditUpdate: SetWindowText(%s)\n"), (LPCSTR) line); } else { // the list box will be closed to show that there is no match ShowDropDown(FALSE); // ?? remove // TRACE(_T("OnEditUpdate: ShowDropDown(false)\n")); // restore the line since the closeup cleared the edit box SetWindowText(line); // ?? remove // TRACE(_T("OnEditUpdate: SetWindowText(%s)\n"), (LPCSTR) line); } // if we are not entering text backwards if(!m_bReverseEntry) { // now set the selection to beyond the last character which // moves the caret to the end SetEditSel(iHiLightStart, -1); // ?? remove // TRACE(_T("OnEditUpdate: SetEditSel(%d, -1)\n"), iHiLightStart); } else { // now set the insertion caret to the beginning so we // build up the text from the right SetEditSel(0, 0); // ?? remove // TRACE(_T("OnEditUpdate: SetEditSel(0, 0)\n")); } // ?? remove // TRACE(_T("EditUpdate SelectedRow: %d Line: %s Matched Text: %s\n") // , m_iSelectedRow, (LPCTSTR) line, (LPCTSTR) sMatchedText); }
本文转载于:http://www.diyabc.com/frontweb/news347.html