文章类型: VC&C++
关键词: VC++,combobox模糊匹配,自动匹配,MFC
内容摘要: VC++ combobox模糊匹配,自动匹配

VC++ combobox模糊匹配,自动匹配

2016/8/29 11:03:42    来源:apple    阅读:

借鉴文章

http://blog.csdn.net/lsldd/article/details/4595386

http://blog.csdn.net/dyzhen/article/details/6185863

谢谢以上两位大神


(1) 使在输入了一个完整的匹配项,或者回车选中某项时,触发CBN_SELCHANGE消息.

(2) ShowDropDown(TRUE)采用消息迂回调用.原因如下,当输入中文词组时,OnEditUpdate会逐字依次调用,也就是说一次性输入几个汉字它就调用几次,而在此当中直接调用ShowDropDown(TRUE)会导致组合框Edit框的内容瞬间变成了匹配选项的内容,且为高亮选中状态,OnEditUpdate接下去处理接下来的汉字的时候,就仅把这一个汉字当成了输入内容,前面的内容就丢失了,所以导致匹配失效. (哎...说的自己都不明白...调试跟踪就知道是咋回事了).

 

本文首先派生了一个CComboBox类CComboCompletion,然后增加虚函数PreTranslateMessage,处理键盘输入,然后增加CBN_DROPDOWN和CBN_EDITUPDATE消息的处理.


头文件:ComboCompletion.h

#if !defined(AFX_COMBOCOMPLETION_H__9255E6D2_71F7_48CD_B6F5_5B249E0BE307__INCLUDED_)  
#define AFX_COMBOCOMPLETION_H__9255E6D2_71F7_48CD_B6F5_5B249E0BE307__INCLUDED_  
  
#if _MSC_VER > 1000  
#pragma once  
#endif // _MSC_VER > 1000  
// ComboCompletion.h : header file  
//  
  
/////////////////////////////////////////////////////////////////////////////  
// CComboCompletion window  
  
#define WM_SHOWDROP WM_USER + 101  
  
class CComboCompletion : public CComboBox  
{  
// Construction  
public:  
    CComboCompletion();  
  
// Attributes  
public:  
  
// Operations  
public:  
  
// Overrides  
    // ClassWizard generated virtual function overrides  
    //{{AFX_VIRTUAL(CComboCompletion)  
    public:  
    virtual BOOL PreTranslateMessage(MSG* pMsg);  
    //}}AFX_VIRTUAL  
  
// Implementation  
public:  
    virtual ~CComboCompletion();  
  
    // Generated message map functions  
protected:  
    //{{AFX_MSG(CComboCompletion)  
    afx_msg void OnDropdown();  
    afx_msg void OnEditupdate();  
    afx_msg HRESULT OnShowDropDown(WPARAM wParam, LPARAM lParam);  
    //}}AFX_MSG  
  
    DECLARE_MESSAGE_MAP()  
private:  
    BOOL m_bAutoComplete;  
};  
  
/////////////////////////////////////////////////////////////////////////////  
  
//{{AFX_INSERT_LOCATION}}  
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.  
  
#endif // !defined(AFX_COMBOCOMPLETION_H__9255E6D2_71F7_48CD_B6F5_5B249E0BE307__INCLUDED_)

源文件:ComboCompletion.cpp

// ComboCompletion.cpp : implementation file  
//  
  
#include "stdafx.h"  
#include "hrinetnsm_con.h"  
#include "ComboCompletion.h"  
  
#ifdef _DEBUG  
#define new DEBUG_NEW  
#undef THIS_FILE  
static char THIS_FILE[] = __FILE__;  
#endif  
  
/////////////////////////////////////////////////////////////////////////////  
// CComboCompletion  
  
CComboCompletion::CComboCompletion()  
{  
}  
  
CComboCompletion::~CComboCompletion()  
{  
}  
  
  
BEGIN_MESSAGE_MAP(CComboCompletion, CComboBox)  
    //{{AFX_MSG_MAP(CComboCompletion)  
    ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)  
    ON_CONTROL_REFLECT(CBN_EDITUPDATE, OnEditupdate)  
    //}}AFX_MSG_MAP  
    ON_MESSAGE(WM_SHOWDROP, OnShowDropDown)  
END_MESSAGE_MAP()  
  
/////////////////////////////////////////////////////////////////////////////  
// CComboCompletion message handlers  
  
BOOL CComboCompletion::PreTranslateMessage(MSG* pMsg)   
{  
    // TODO: Add your specialized code here and/or call the base class  
    if (pMsg->message == WM_CHAR)  
    {  
        m_bAutoComplete = TRUE;  
  
        int nVirKey = pMsg->wParam;  
  
        switch (nVirKey)  
        {  
        case VK_RETURN:  
            {  
                // 关闭下拉框  
                ShowDropDown(FALSE);  
                  
                CString strLine;  
                GetWindowText(strLine);  
                  
                // 回车即选中高亮项  
                SelectString(-1, strLine);  
                  
                // 给父窗口发送选项改变的消息  
                WPARAM wParam = MAKELPARAM(GetDlgCtrlID(), CBN_SELCHANGE);  
                GetParent()->PostMessage(WM_COMMAND, wParam, (LPARAM)m_hWnd);  
  
                break;  
            }  
  
        case VK_DELETE:  
        case VK_BACK:  
  
            m_bAutoComplete = FALSE;  
  
            break;  
  
        default:  
            break;  
        }  
  
    }  
  
    return CComboBox::PreTranslateMessage(pMsg);  
}  
  
void CComboCompletion::OnDropdown()   
{  
    // TODO: Add your control notification handler code here  
  
    SetCursor(LoadCursor(NULL, IDC_ARROW));       
}  
  
void CComboCompletion::OnEditupdate()   
{  
    // TODO: Add your control notification handler code here  
    CString strLine;  
      
    GetWindowText(strLine);    
      
    int iHiLightStart = strLine.GetLength();    
      
    if(strLine.GetLength() == 0)     
    {    
        ShowDropDown(FALSE);    
          
        SetWindowText(_T(""));     
          
        m_bAutoComplete = TRUE;    
  
        return;    
    }    
    // 处理删除操作   
    if(!m_bAutoComplete)    
    {    
        m_bAutoComplete = TRUE;    
  
        return;    
    }    
    // 开始匹配用户输入    
    int iSelectedRow = FindString(-1, strLine);    
      
    if(iSelectedRow >= 0)    
    {  
//          ShowDropDown(TRUE);    
        PostMessage(WM_SHOWDROP, 0, 0);  
  
        // 匹配的选项被选中    
        PostMessage(CB_SETCURSEL, iSelectedRow, 0);    
          
        // 给父窗口发送选项改变的消息,这样可以保证当输入完整的匹配的部门时,不用回车也触发部门改变消息  
        WPARAM wParam = MAKELPARAM(GetDlgCtrlID(), CBN_SELCHANGE);  
        GetParent()->PostMessage(WM_COMMAND, wParam, (LPARAM)m_hWnd);  
  
    }    
    else     
    {    
//         ShowDropDown(FALSE);    
//         SetWindowText(strLine);    
    }    
    // 高亮自动完成的部分  
    PostMessage(CB_SETEDITSEL, 0, MAKELPARAM(iHiLightStart, -1));    
}  
  
HRESULT CComboCompletion::OnShowDropDown(WPARAM wParam, LPARAM lParam)  
{  
      
    ShowDropDown(TRUE);  
      
    return 0;  
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

后来发现这个类还是不能满足条件,如果希望输入首字母,自动补全的同时还要删除无关信息,终于在pudn找到一个

头文件:AutoCombox1.h

#pragma once  
  
  
// CAutoCombox1  
  
class CAutoCombox1 : public CComboBox  
{  
    DECLARE_DYNAMIC(CAutoCombox1)  
  
public:  
    CAutoCombox1();  
    virtual ~CAutoCombox1();  
  
    // manipulating listbox items  
    int AddString(LPCTSTR lpszString);  
    int DeleteString(UINT nIndex);  
    int InsertString(int nIndex, LPCTSTR lpszString);  
    void ResetContent();  
  
    //set state  
    void SetFlag(UINT nFlag)  
    {m_nFlag = nFlag;}  
  
private:  
    int Dir(UINT attr, LPCTSTR lpszWildCard)  
    {ASSERT(FALSE);}//forbidden  
  
protected:  
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);  
    void AutoSelect();  
    void AutoMatchAndSel();  
  
    DECLARE_MESSAGE_MAP()  
  
private:  
    CEdit* m_pEdit; //edit control  
    UINT m_nFlag;   //some flag  
                    //bit 0: 0 is show all, 1 is remove not matching, if no maching, show all.  
    CStringArray m_strArr;  
};

源文件:AutoCombox1.cpp

// AutoCombox1.cpp : implementation file  
//  
  
#include "stdafx.h"  
// #include "MyCombox.h"  
#include "AutoCombox1.h"  
  
  
// CAutoCombox1  
  
IMPLEMENT_DYNAMIC(CAutoCombox1, CComboBox)  
  
CAutoCombox1::CAutoCombox1()  
{  
    m_pEdit = NULL;  
    m_nFlag = 0;  
}  
  
CAutoCombox1::~CAutoCombox1()  
{  
    if (m_pEdit)  
    {  
        if (::IsWindow(m_hWnd))  
        {  
            m_pEdit->UnsubclassWindow();  
        }  
        delete m_pEdit;  
        m_pEdit = NULL;  
    }  
}  
  
  
BEGIN_MESSAGE_MAP(CAutoCombox1, CComboBox)  
END_MESSAGE_MAP()  
  
  
  
// CAutoCombox1 message handlers  
  
  
//自动选择最匹配的,如果没有,则不选择。////////////////////////////////  
void CAutoCombox1::AutoSelect()  
{  
    // Make sure we can 'talk' to the edit control  
    if ( m_pEdit == NULL )    
    {  
        m_pEdit = new CEdit();  
        m_pEdit->SubclassWindow(GetDlgItem(1001)->GetSafeHwnd());  
    }  
  
    // Save the state of the edit control  
    CString strText;            //取得输入字符串  
    int nStart = 0, nEnd = 0;   //取得光标位置  
    m_pEdit->GetWindowText(strText);  
    m_pEdit->GetSel(nStart, nEnd);  
  
    // Perform actual completion  
    int nBestIndex = -1;        //是否能找到匹配的字符  
    int nBestFrom  = INT_MAX;   //匹配开始的字符  
  
    if (!strText.IsEmpty())  
    {  
        for ( int nIndex=0; nIndex<GetCount(); ++nIndex )  
        {  
            CString str;  
            GetLBText(nIndex,str);  
  
            int nFrom = str.Find(strText);  
  
            if ( nFrom != -1 && nFrom < nBestFrom )//能匹配,而且是更好的匹配,才记录  
            {  
                nBestIndex = nIndex;  
                nBestFrom  = nFrom;  
            }  
        }//for  
    }  
  
    //Set select index  
    if (!GetDroppedState())  
    {  
        ShowDropDown(TRUE);  
        m_pEdit->SetWindowText(strText);  
        m_pEdit->SetSel(nStart, nEnd);  
    }  
  
    if ( GetCurSel() != nBestIndex )  
    {  
        // Select the matching entry in the list  
        SetCurSel(nBestIndex);  
  
        // Restore the edit control  
        m_pEdit->SetWindowText(strText);  
        m_pEdit->SetSel(nStart, nEnd);  
    }  
}  
  
//删除不匹配的,自动选择剩余中最匹配的,如果没有,则显示全部。//////////////  
void CAutoCombox1::AutoMatchAndSel()  
{  
    // Make sure we can 'talk' to the edit control  
    if ( m_pEdit == NULL )    
    {  
        m_pEdit = new CEdit();  
        m_pEdit->SubclassWindow(GetDlgItem(1001)->GetSafeHwnd());  
    }  
  
    // 保存edit控件的状态  
    CString strText;            //取得输入字符串  
    int nStart = 0, nEnd = 0;   //取得光标位置  
    m_pEdit->GetWindowText(strText);  
    m_pEdit->GetSel(nStart, nEnd);  
  
    //清空CComboBox里面的数据  
    CComboBox::ResetContent();  
  
    // 重新填充列表,并选择最合适的  
    int nBestIndex = -1;        //是否能找到匹配的字符  
    int nBestFrom  = INT_MAX;   //匹配开始的字符  
  
    if (!strText.IsEmpty())  
    {  
        for ( int nIndex=0; nIndex<m_strArr.GetSize(); ++nIndex )  
        {  
            int nFrom = m_strArr[nIndex].Find(strText);  
            char kk = m_strArr[nIndex].GetAt(0);  
            char jj = strText.GetAt(0);  
            BOOL flag = FALSE;  
            if (kk==jj)  
            {  
                flag = TRUE;  
            }  
            if ( nFrom != -1&&flag==TRUE)//能匹配  
            {  
                int n = CComboBox::AddString(m_strArr[nIndex]);  
  
                if (nFrom < nBestFrom)//更好的匹配,则记录  
                {  
                    nBestIndex = n;  
                    nBestFrom  = nFrom;  
                }  
            }  
        }//for  
    }  
  
    if (GetCount() == 0)    //没有的显示所有  
    {  
        for (int nIndex=0; nIndex<m_strArr.GetSize(); ++nIndex)  
        {  
            CComboBox::AddString(m_strArr[nIndex]);  
        }  
    }  
  
    //显示下拉列表  
    if (!GetDroppedState())  
    {  
        ShowDropDown(TRUE);  
    }  
  
    //设置选择项  
    // Select and Restore the edit control  
    SetCurSel(nBestIndex);  
    m_pEdit->SetWindowText(strText);  
    m_pEdit->SetSel(nStart, nEnd);  
}  
// manipulating listbox items  
int  CAutoCombox1::AddString(LPCTSTR lpszString)  
{  
    m_strArr.Add(lpszString);  
    return CComboBox::AddString(lpszString);  
}  
int  CAutoCombox1::DeleteString(UINT nIndex)  
{  
    m_strArr.RemoveAt(nIndex);  
    return CComboBox::DeleteString(nIndex);  
}  
int  CAutoCombox1::InsertString(int nIndex, LPCTSTR lpszString)  
{  
    m_strArr.InsertAt(nIndex, lpszString);  
    return CComboBox::InsertString(nIndex, lpszString);  
}  
void  CAutoCombox1::ResetContent()  
{  
    m_strArr.RemoveAll();  
    CComboBox::ResetContent();  
}  
  
//All Message Handle Dispatch  
BOOL CAutoCombox1::OnCommand(WPARAM wParam, LPARAM lParam)  
{  
    if ( HIWORD(wParam) == EN_CHANGE )  
    {     
        if (m_nFlag & 0x01)  
        {  
            AutoMatchAndSel();  
        }  
        else  
        {  
            AutoSelect();  
        }  
        return true;  
    }  
    else  
    {  
        return CComboBox::OnCommand(wParam, lParam);  
    }  
}

本文的程序源码下载:AutoComboBox_模糊匹配&自动匹配 (提取码:8353)

↑ 上一篇文章:VC UI界面库大集合 关键词:VC,UI界面库大集合 发布日期:2016/8/29 9:30:50
↓ 下一篇文章:VC中设置button按钮的Visible和Disabled可用和不可用 关键词:VC中设置button按钮的Visible和Disabl.. 发布日期:2016/8/30 10:48:40
相关文章:
MFC应用程序框架入门 关键词:VC,VC++6.0,MFC,程序框架 发布日期:2016-10-10 11:49
VC++ MFC DLL动态链接库编写详解 关键词:VC++,MFC,DLL,动态链接库,编写,详解 发布日期:2016-08-19 10:45
vc++ mfc下访问http的类,接口非常简单,很好用 关键词:vc++,mfc下访问http的类,接口非常简单,很好用 发布日期:2016-08-23 14:03
相关目录:.NETVC&C++软件开发
我要评论
正在加载评论信息......