1. 程式人生 > 實用技巧 >多列自動完成組合框

多列自動完成組合框

介紹 一個組合框,具

有自動完成功能,也允許多個 列。它來源於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