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