美文网首页
模糊搜索 支持虚拟键盘输入 定制组合框 MFC

模糊搜索 支持虚拟键盘输入 定制组合框 MFC

作者: 风轻云淡宇 | 来源:发表于2023-03-30 01:14 被阅读0次
    1. 背景

    用 MFC 的组合框可以做出很好模糊搜索效果,但有个硬伤,当用虚拟键盘输入时,组合框会因失去焦点自动收缩,无法展现想要搜索的项,所以就用 CEdit 和 CListBox 定制了一个支持虚拟键盘输入的模糊搜索组合框。

    2.具体实现
    2.1 具体界面布局如下:
    界面布局

    从工具箱拖拽一个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) 一样。

    相关文章

      网友评论

          本文标题:模糊搜索 支持虚拟键盘输入 定制组合框 MFC

          本文链接:https://www.haomeiwen.com/subject/ruqykdtx.html