借鉴文章
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/