多列自动完成组合框

介绍 一个组合框,具

  

有自动完成功能,也允许多个 列。它来源于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

原文地址:https://www.cnblogs.com/Dincat/p/13438178.html