多列自動完成組合框
介紹 一個組合框,具
有自動完成功能,也允許多個 列。它來源於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