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

借鉴文章

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);
	}
}

=================================================================================================================

程序猿和程序媛必备的咖啡-OneDay咖啡生活-https://shop110384469.taobao.com/


  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值