在VS2010下,通過MFC用EditBox + ListBox自制ComboBox(附加簡單的模糊搜索功能)

       我在用MFC學習開發一些小工具時,使用過很多次ComboBox控件。雖然ComboBox很好用,新增的Ex還可以插入圖片,

但是有時遇到某些細節上的操作,會發現ComboBox控制起來還是很不自在,而且很難修改。

例如:我想通過在ComboBox的文本框輸入字符串,即可在下拉菜單下搜索匹配的一項(模糊搜索),但不知道爲什麼

總是指向該項時總是把文本框原有的輸入覆蓋掉(可能是默認自動選擇寫入文本框),文本框和下拉菜單之間功能實施綁

定在一起,暫時不知道如何各自分開控制(我並不想在下拉菜單上下移動時就給文本框賦值,求高手指導此解決方法)。

於是自制一個EditBox + ListBox合成的模擬ComboBox,這樣的好處就是操作上可以分開控制,而且我還可以幾個EditBox

共同控制同一個ListBox(可以根據EditBox的焦點指向方法響應,然後獲取ListBox的位置,最後顯示)。


操作上主要在PreTranslateMessage中通過控制焦點和指定的消息響應實現,代碼如下:

BOOL CTestMyComboDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加專用代碼和/或調用基類

	if (GetFocus() != GetDlgItem(IDC_EDIT1) && GetFocus() != GetDlgItem(IDC_LIST1))
	{
		m_List1.ShowWindow(SW_HIDE);
	}
	else
	{
		m_List1.ShowWindow(SW_SHOW);
	}

	if(WM_LBUTTONUP == pMsg->message)
	{
		if (GetFocus() == GetDlgItem(IDC_LIST1))
		{
			SetEditText(); //該方法是把ListBox當前選擇寫入文本框
		}
	}

	if (VK_DOWN == pMsg->wParam)
	{
		if (GetFocus() == GetDlgItem(IDC_EDIT1))
		{
			m_List1.SetFocus();
			m_List1.SetCurSel(m_List1.GetCurSel() + 1);
		}
		if ((GetFocus()->GetParent()) == GetDlgItem(IDC_COMBO1))
		{
			m_Combo1.SetCurSel(m_Combo1.GetCurSel() + 1);
		}
	}

	if (VK_UP == pMsg->wParam)
	{
		if (GetFocus() == GetDlgItem(IDC_EDIT1))
		{
			m_List1.SetFocus();

			if (m_List1.GetCurSel() > 0)
			{
				m_List1.SetCurSel(m_List1.GetCurSel() - 1);
			}
			else
			{
				m_List1.SetCurSel(0);
			}
		}
	}

	if (VK_RETURN == pMsg->wParam)
	{
		if (GetFocus() == GetDlgItem(IDC_EDIT1) || GetFocus() == GetDlgItem(IDC_LIST1))
		{
			SetEditText();
		}
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}


在EditBox中輸入數據時,自動搜索ListBox選項,可以通過EditBox的OnEnChange方法響應,再獲取數據進行搜索實現:

void CTestMyComboDlg::OnEnChangeEdit1()
{
	// TODO:  在此添加控件通知處理程序代碼
	CString strEdit;

	m_Edit1.GetWindowText(strEdit);

	if (!strEdit.IsEmpty())
	{
		if (m_List1.SelectString(0, strEdit) == CB_ERR)   //先用SelectString進行首字母匹配,如果匹配失敗再進行模糊匹配
		{
			SetFuzzyQuery(strEdit);    //模糊匹配方法
		}

	}
	else
	{
		m_List1.SetCurSel(-1);
	}
}

簡單的模糊匹配方法,就是獲取ListBox的每一項字符串,然後通過CString::Find方法與要匹配的字符串進行比較(如果希望不分大小寫方式匹配,

可以在比較前把兩字符串先MakeUpper一下)。

int CTestMyComboDlg::SetFuzzyQuery(CString csEdit)
{
	CString csTemp;
	int iListTotal = m_List1.GetCount();

	csEdit.MakeUpper();
	for (int iTemp = 0; iTemp < iListTotal; iTemp++)
	{
		m_List1.GetText(iTemp, csTemp);
		csTemp.MakeUpper();
		if (csTemp.Find(csEdit.GetBuffer()) != -1)
		{
			m_List1.SetCurSel(iTemp);
			break;
		}
	}

	return 0;
}


有興趣可以參考本人的原測試工程:

http://download.csdn.net/detail/dante_vanc/4436120


本人編程新手,比較愚昧,以上內容如有問題或者更好的提議,歡迎提出。小弟非常樂意接受各位的指點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章