1. 背景
用 MFC 的组合框可以做出很好模糊搜索效果,但有个硬伤,当用虚拟键盘输入时,组合框会因失去焦点自动收缩,无法展现想要搜索的项,所以就用 CEdit 和 CListBox 定制了一个支持虚拟键盘输入的模糊搜索组合框。
2.具体实现
2.1 具体界面布局如下:
![](https://img.haomeiwen.com/i7186199/8b1f9495e6b056da.png)
从工具箱拖拽一个CEdit和CListbox,并在CListbox下放四个按钮,用于演示下拉框收起时效果。
2.2 给下拉框添加数据
for (int i = 0; i < 100; i++)
{
CString strData;
srand((unsigned)time(NULL));
strData.Format(_T("%d 内容%d"), rand()*(i+1), i);
m_listBox.AddString(strData);
}
这里随意添加一些数据到下拉框中。
2.3 监测编辑框输入变化的函数实现如下:
void CCboxCustmerDlg::OnEnChangeInput()
{
CString strInput;
ShowCbList(TRUE);
m_bFind = FALSE;
m_editInput.GetWindowText(strInput);
if (!strInput.IsEmpty())
{
if (m_listBox.SelectString(-1, strInput) == CB_ERR)
{
Query(strInput);
}
else
{
CString strResult;
m_listBox.SetCurSel(m_listBox.GetCurSel());
m_listBox.GetText(m_listBox.GetCurSel(), strResult);
m_bFind = FALSE;
}
}
else
{
m_listBox.SetCurSel(-1);
}
}
- ShowCbList(TRUE) 的作用:当编辑框有输入时,显示下拉框,并隐藏和下拉框同区域的其它控件
- ShowCbList(TRUE) 函数的具体实现如下
void CCboxCustmerDlg::ShowCbList(BOOL bShow)
{
if (bShow)
{
m_listBox.ShowWindow(SW_SHOW);
GetDlgItem(IDB_TEST1)->ShowWindow(SW_HIDE);
GetDlgItem(IDB_TEST2)->ShowWindow(SW_HIDE);
GetDlgItem(IDB_TEST3)->ShowWindow(SW_HIDE);
GetDlgItem(IDB_TEST4)->ShowWindow(SW_HIDE);
}
else
{
m_listBox.ShowWindow(SW_HIDE);
GetDlgItem(IDB_TEST1)->ShowWindow(SW_SHOW);
GetDlgItem(IDB_TEST2)->ShowWindow(SW_SHOW);
GetDlgItem(IDB_TEST3)->ShowWindow(SW_SHOW);
GetDlgItem(IDB_TEST4)->ShowWindow(SW_SHOW);
}
}
- 当输入框中内容不为空时,用 CListBox 类函数 SelectString 搜索,参数 -1 表示从列表的第 1 个项开始搜索(固定从每个项对应字符串第 1 个字符开始匹配)如匹配到,则选中对应的项,如当匹配不到时,需要继续用 CString 类的 Find 函数搜索,找到任何含有被搜索字符串的项,则选中:
BOOL CCboxCustmerDlg::Query(CString strFind)
{
CString strTemp;
int iListTotal = m_listBox.GetCount();
strFind.MakeUpper();
for (int iTemp = 0; iTemp < iListTotal; iTemp++)
{
m_listBox.GetText(iTemp, strTemp);
strTemp.MakeUpper();
if (strTemp.Find(strFind.GetBuffer()) != -1)
{
m_bFind = TRUE;
m_listBox.SetCurSel(iTemp);
return TRUE;
}
}
return FALSE;
}
2.4 以下对鼠标和键盘消息处理很关键,也很考验对 Windows 消息的处理能力,代码如下:
BOOL CCboxCustmerDlg::PreTranslateMessage(MSG* pMsg)
{
if (WM_LBUTTONDOWN == pMsg->message)
{
if (pMsg->hwnd != GetDlgItem(IDC_LIST)->m_hWnd && pMsg->hwnd != GetDlgItem(IDE_INPUT)->m_hWnd)
{
SetFocus();
ShowCbList(FALSE);
}
}
else if (WM_LBUTTONUP == pMsg->message)
{
if (GetFocus() == GetDlgItem(IDC_LIST))
{
SetEditText();
SetFocus();
ShowCbList(FALSE);
}
else if (GetFocus() == GetDlgItem(IDE_INPUT))
{
if (m_bFind)
{
m_bFind = FALSE;
ShowCbList(FALSE);
}
}
}
if (VK_DOWN == pMsg->wParam)
{
if (GetFocus() == GetDlgItem(IDE_INPUT))
{
m_listBox.SetFocus();
m_listBox.SetCurSel(m_listBox.GetCurSel() + 1);
}
}
else if (VK_UP == pMsg->wParam)
{
if (GetFocus() == GetDlgItem(IDE_INPUT))
{
m_listBox.SetFocus();
if (m_listBox.GetCurSel() > 0)
{
m_listBox.SetCurSel(m_listBox.GetCurSel() - 1);
}
else
{
m_listBox.SetCurSel(0);
}
}
}
if (VK_RETURN == pMsg->wParam)
{
if (GetFocus() == GetDlgItem(IDE_INPUT) || GetFocus() == GetDlgItem(IDC_LIST))
{
SetEditText();
ShowCbList(FALSE);
}
return FALSE;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
- WM_LBUTTONDOWN 鼠标按下消息的处理:当焦点不在输入框和下拉框时,将下拉框隐藏,并将输入焦点设为主窗口;
这里将输入焦点置为主窗口,因为输入框为 TAB 序第一个可输入的控件,实际是将输入焦点指向为输入框,所有此时输入框如果有内容会被全选(应该是) - WM_LBUTTONUP 鼠标弹起消息的处理:当焦点在下拉框上时,将下拉框中被选中的项对应字符串显示到输入框中,并隐藏下拉框;
- VK_DOWN 和 VK_UP 向上向下键:可控制下拉框向下或向上移动选中的项
- 回车键:当焦点在输入框或者下拉框上时,其效果和鼠标按下消息( WM_LBUTTONUP) 一样。
网友评论