
经过两天的编码调试,完成了一个自动过滤选择的组合框,具有以下优点: 1。丝毫不妨碍组合框原有的功能 2。根据用户在编辑框里已经输入的单词,从组合框的列表选项过滤出匹配的项,并使用下拉列表显示出来以供用户选择。 3。不需要特别的设置。从View\ClassWizard\Member Variables里生成一个CComboBox,然后在源文件里把CComboBox替换成CACComboBox即可;或者让ClassWizard认识CACComboBox(删除MyApp.clw,选View\ClassWizard,按提示重新生成MyApp.clw,绝大多数时候能成功),从View\ClassWizard\Member Variables里直接生成一个CACComboBox。 4。你可以经过简单修改使之成为具有其他类似功能(自动填写??)的组合框。
由于时间仓促,没有写详细的注释。感兴趣的朋友请等几天后向我索要。联系方法: [email protected]
代码如下:
file://----------------------------------------------------------------------------- // File: ACComboBox.h // // Desc: // 根据用户在编辑框里已经输入的单词,从组合框的列表选项过滤出匹配的项,并使用下拉列表显示出来以供用户选择 // // Copyright (c) 2001 EagleFly Studio. // // Original Author: Zhengpeng.Lan // Author: // // Create Time: 2001/10/10 // Modify Time: 2001/10/11 // file://----------------------------------------------------------------------------- #if !defined(AFX_ACCOMBOBOX_H__81CBBD04_3955_4076_A688_74D3EA9730D9__INCLUDED_) #define AFX_ACCOMBOBOX_H__81CBBD04_3955_4076_A688_74D3EA9730D9__INCLUDED_
#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000
#include "afxtempl.h"
// ACComboBox.h : header file // class CACComboBox; ///////////////////////////////////////////////////////////////////////////// // CWndForACComboBox window typedef struct { int nid; CString strDepict; }CInfoForACComboBox;
typedef CArray<CInfoForACComboBox,CInfoForACComboBox &> CInfoForACComboBoxArray;
class CWndForACComboBox : public CWnd { friend CACComboBox; private: // Construction LPCTSTR lpWndCls; // Construction public: CWndForACComboBox();
// Attributes public: CComboBox * m_pComboBox; int m_nMaxCount; CInfoForACComboBoxArray m_aInfo; int m_nMousePos; int m_nBeginShow;
inline void RemoveAll() { m_aInfo.RemoveAll(); CWnd::SetScrollRange(SB_VERT,0,0); } inline void Add(CInfoForACComboBox &info) { m_aInfo.Add(info); } inline int GetSize() { return m_aInfo.GetSize(); } inline void ShowList() { if(IsWindow(GetSafeHwnd())) { ShowWindow(SW_SHOWNOACTIVATE); } } // Operations public:
// Overrides // ClassWizard generated virtual function overrides file://{{AFX_VIRTUAL(CWndForACComboBox) public: virtual BOOL Create(CComboBox * pWnd); file://}}AFX_VIRTUAL
// Implementation public: virtual ~CWndForACComboBox();
// Generated message map functions protected: file://{{AFX_MSG(CWndForACComboBox) afx_msg void OnDestroy(); afx_msg void OnPaint(); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); file://}}AFX_MSG DECLARE_MESSAGE_MAP() };
///////////////////////////////////////////////////////////////////////////// // CACComboBox window
class CACComboBox : public CComboBox { private: CEdit* m_pEdit;
// Construction public: CACComboBox();
// Attributes public: CWndForACComboBox m_wndList; inline void WindowMove(void) { if(IsWindow(m_wndList.GetSafeHwnd())) m_wndList.Invalidate(FALSE); } // Operations public: virtual void HandleCompletion();
// Overrides // ClassWizard generated virtual function overrides file://{{AFX_VIRTUAL(CACComboBox) protected: virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); virtual void PreSubclassWindow(); file://}}AFX_VIRTUAL
// Implementation public: virtual ~CACComboBox();
// Generated message map functions protected: file://{{AFX_MSG(CACComboBox) afx_msg void OnKillfocus(); afx_msg void OnSelchange(); file://}}AFX_MSG
DECLARE_MESSAGE_MAP() };
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// file://{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_ACCOMBOBOX_H__81CBBD04_3955_4076_A688_74D3EA9730D9__INCLUDED_)
file://----------------------------------------------------------------------------- // File: ACComboBox.cpp // // Desc: // 根据用户在编辑框里已经输入的单词,从组合框的列表选项过滤出匹配的项,并使用下拉列表显示出来以供用户选择 // // Copyright (c) 2001 EagleFly Studio. // // Original Author: Zhengpeng.Lan // Author: // // Create Time: 2001/10/10 // Modify Time: 2001/10/11 // file://-----------------------------------------------------------------------------
#include "stdafx.h" #include "ACComboBox.h"
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
///////////////////////////////////////////////////////////////////////////// // CACComboBox
CACComboBox::CACComboBox() :CComboBox() { m_pEdit = NULL; }
CACComboBox::~CACComboBox() { if(m_pEdit) delete m_pEdit; }
BEGIN_MESSAGE_MAP(CACComboBox, CComboBox) file://{{AFX_MSG_MAP(CACComboBox) ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillfocus) ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange) file://}}AFX_MSG_MAP END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CACComboBox message handlers ///////////////////////////////////////////////////////////////////////////// // CWndForACComboBox
CWndForACComboBox::CWndForACComboBox() :CWnd() { lpWndCls = AfxRegisterWndClass(0); m_pComboBox = NULL; m_nMaxCount = 8; m_aInfo.SetSize(0,8); m_nMousePos = -1; m_nBeginShow = 0; }
CWndForACComboBox::~CWndForACComboBox() {
}
BEGIN_MESSAGE_MAP(CWndForACComboBox, CWnd) file://{{AFX_MSG_MAP(CWndForACComboBox) ON_WM_DESTROY() ON_WM_PAINT() ON_WM_KEYDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEWHEEL() ON_WM_KILLFOCUS() ON_WM_MOUSEMOVE() ON_WM_VSCROLL() file://}}AFX_MSG_MAP END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CWndForACComboBox message handlers
BOOL CWndForACComboBox::Create(CComboBox * pWnd) { ASSERT(pWnd);
CRect rect; CWnd * pParentWnd = pWnd->GetParent();
pWnd->GetWindowRect(&rect); // pParentWnd->ScreenToClient(&rect);
BOOL bRet = CWnd::CreateEx( WS_EX_TOPMOST | WS_EX_TOOLWINDOW,\ lpWndCls, NULL, WS_POPUP | WS_VSCROLL, rect.left, rect.top, rect.Width(), rect.Height(), pParentWnd->GetSafeHwnd(), NULL, NULL);
if(bRet) SetOwner(pParentWnd);
m_pComboBox = pWnd; return bRet; }
void CWndForACComboBox::OnDestroy() { CWnd::OnDestroy(); m_aInfo.RemoveAll(); }
void CWndForACComboBox::OnPaint() { CRect rect; CFont * pFont; LOGFONT logFont;
if(m_pComboBox) { ASSERT(::IsWindow(m_pComboBox->GetSafeHwnd())); CWnd * pParentWnd = m_pComboBox->GetParent(); m_pComboBox->GetWindowRect(&rect); pFont = pParentWnd->GetFont(); ASSERT(pFont); pFont->GetLogFont(&logFont);
if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight; if(m_aInfo.GetSize() > m_nMaxCount) { logFont.lfWidth = m_nMaxCount * logFont.lfHeight; } else { logFont.lfWidth = m_aInfo.GetSize() * logFont.lfHeight; } if(logFont.lfWidth + rect.bottom > ::GetSystemMetrics(SM_CYSCREEN)) { rect.bottom = rect.top; rect.top = rect.bottom - logFont.lfWidth - 2; if(rect.top < 0) rect.top = 0; } else { rect.top = rect.bottom; rect.bottom = rect.top + logFont.lfWidth + 2; } rect.right = rect.left + m_pComboBox->GetDroppedWidth(); // pParentWnd->ScreenToClient(&rect); MoveWindow(&rect); if(rect.Height() < m_aInfo.GetSize() * logFont.lfHeight) { TRACE("%d %d\r\n",rect.Height(),m_aInfo.GetSize() * logFont.lfHeight); SCROLLINFO info;
info.cbSize = sizeof(info); info.fMask = SIF_PAGE; info.nPage = rect.Height() / logFont.lfHeight; CWnd::SetScrollRange(SB_VERT,0,m_aInfo.GetSize() - 1,FALSE); CWnd::ShowScrollBar(SB_VERT,TRUE); CWnd::SetScrollInfo(SB_VERT,&info); } else { CWnd::ShowScrollBar(SB_VERT,FALSE); } } CPaintDC dc(this); // device context for painting
file://dc.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255)); dc.Rectangle(0,0,rect.Width(),rect.Height()); logFont.lfWidth = 1; dc.SelectObject(pFont); int m_nBeginShow = CWnd::GetScrollPos(SB_VERT); for(int i=m_nBeginShow;i<m_aInfo.GetSize() && logFont.lfWidth < rect.Height() - 2;i++) { if(i == m_nMousePos) { dc.SetBkColor(RGB(0,0,128)); dc.FillSolidRect(1,logFont.lfWidth,rect.Width() - 2,logFont.lfHeight,RGB(0,0,128)); dc.SetTextColor(RGB(255,255,255)); } else { dc.SetBkColor(RGB(255,255,255)); dc.SetTextColor(RGB(0,0,0)); } dc.TextOut(3,logFont.lfWidth,m_aInfo[i].strDepict); logFont.lfWidth += logFont.lfHeight; } }
void CWndForACComboBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default CWnd::OnKeyDown(nChar, nRepCnt, nFlags); }
void CWndForACComboBox::OnLButtonUp(UINT nFlags, CPoint point) { CFont * pFont; LOGFONT logFont;
if(m_pComboBox) { pFont = m_pComboBox->GetParent()->GetFont(); pFont->GetLogFont(&logFont); if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight; m_nMousePos = (point.y - 1) / logFont.lfHeight + CWnd::GetScrollPos(SB_VERT); if(m_nMousePos >= 0 && m_nMousePos < m_aInfo.GetSize()) m_pComboBox->SetCurSel(m_aInfo[m_nMousePos].nid); ShowWindow(SW_HIDE); } CWnd::OnLButtonUp(nFlags, point); }
BOOL CWndForACComboBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: Add your message handler code here and/or call default return CWnd::OnMouseWheel(nFlags, zDelta, pt); }
void CWndForACComboBox::OnKillFocus(CWnd* pNewWnd) { CWnd::OnKillFocus(pNewWnd); if(pNewWnd->GetSafeHwnd() != m_pComboBox->GetSafeHwnd() && pNewWnd->GetSafeHwnd() != GetSafeHwnd() && IsWindow(GetSafeHwnd())) ShowWindow(SW_HIDE); }
void CWndForACComboBox::OnMouseMove(UINT nFlags, CPoint point) { CFont * pFont; LOGFONT logFont; ::ShowCursor(TRUE); if(m_pComboBox) { pFont = m_pComboBox->GetParent()->GetFont(); pFont->GetLogFont(&logFont); if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight; logFont.lfWidth = point.y / logFont.lfHeight + CWnd::GetScrollPos(SB_VERT); if(logFont.lfWidth != m_nMousePos) { m_nMousePos = logFont.lfWidth; Invalidate(); } } CWnd::OnMouseMove(nFlags, point); }
void CWndForACComboBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if(m_aInfo.GetSize() <= 0) { CWnd::OnVScroll(nSBCode, nPos, pScrollBar); return ; }
switch(nSBCode) { // case SB_BOTTOM://Scroll to bottom. // case SB_ENDSCROLL://End scroll. case SB_LINEDOWN://Scroll one line down. { RECT rc; LOGFONT logFont; CFont * pFont;
GetClientRect(&rc); pFont = m_pComboBox->GetParent()->GetFont(); pFont->GetLogFont(&logFont); ASSERT(logFont.lfHeight != 0); if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight; rc.left = (rc.bottom - rc.top) / logFont.lfHeight;
int nPos = GetScrollPos(SB_VERT) + 1; if(nPos + rc.left <= m_aInfo.GetSize()) { SetScrollPos(SB_VERT,nPos); Invalidate(); } } break; case SB_LINEUP://Scroll one line up. { int nPos = GetScrollPos(SB_VERT) - 1; if(nPos >= 0) { SetScrollPos(SB_VERT,nPos); Invalidate(); } } break; case SB_PAGEDOWN://Scroll one page down. { RECT rc; LOGFONT logFont; CFont * pFont;
GetClientRect(&rc); pFont = m_pComboBox->GetParent()->GetFont(); pFont->GetLogFont(&logFont); ASSERT(logFont.lfHeight != 0); if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight;
rc.top = rc.bottom / logFont.lfHeight; int nPos = GetScrollPos(SB_VERT); if(nPos < m_aInfo.GetSize() - rc.top) { nPos += rc.top; if(nPos > m_aInfo.GetSize() - rc.top) nPos = m_aInfo.GetSize() - rc.top; SetScrollPos(SB_VERT,nPos); Invalidate(); } } break; case SB_PAGEUP://Scroll one page up. { RECT rc; LOGFONT logFont; CFont * pFont;
GetClientRect(&rc); pFont = m_pComboBox->GetParent()->GetFont(); pFont->GetLogFont(&logFont); ASSERT(logFont.lfHeight != 0); if(logFont.lfHeight < 0) logFont.lfHeight = -logFont.lfHeight;
rc.top = rc.bottom / logFont.lfHeight; int nPos = GetScrollPos(SB_VERT); if(nPos > 0) { nPos -= rc.top; if(nPos < 0) nPos = 0; SetScrollPos(SB_VERT,nPos); Invalidate(); } } break; // case SB_THUMBPOSITION://Scroll to the absolute position. The current position is provided in nPos. case SB_THUMBTRACK://Drag scroll box to specified position. The current position is provided in nPos. { SetScrollPos(SB_VERT,nPos); Invalidate(); } break; // case SB_TOP://Scroll to top } CWnd::OnVScroll(nSBCode, nPos, pScrollBar); }
void CACComboBox::HandleCompletion() { // 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 text,bestText; CInfoForACComboBox info; int n = GetCount();
m_wndList.RemoveAll(); m_pEdit->GetWindowText(text); CPoint ptCaret = m_pEdit->GetCaretPos();
// int start,end; // m_pEdit->GetSel(start,end);
// Perform actual completion int bestindex = -1; int bestfrom = INT_MAX; int from; for ( int x = 0; x < n; x++ ) { GetLBText(x,info.strDepict); info.nid = x;
from = info.strDepict.Find(text);
if(from != -1) { m_wndList.Add(info); if( from != -1 && from < bestfrom ) { bestindex = x; bestText = info.strDepict; bestfrom = from; } } }
if ( bestindex != -1) { // Restore the edit control m_pEdit->SetWindowText(bestText); m_pEdit->SetSel(text.GetLength(),bestText.GetLength()); m_pEdit->SetCaretPos(ptCaret); } if(m_wndList.GetSize() != 0) { m_wndList.ShowList(); m_wndList.Invalidate(); } else { m_wndList.ShowWindow(SW_HIDE); } }
BOOL CACComboBox::OnCommand(WPARAM wParam, LPARAM lParam) { if(HIWORD(wParam) == EN_CHANGE) { HandleCompletion(); return TRUE; } return CComboBox::OnCommand(wParam, lParam); }
void CACComboBox::PreSubclassWindow() { CComboBox::PreSubclassWindow();
m_wndList.Create(this); }
void CACComboBox::OnKillfocus() { m_wndList.OnKillFocus(GetFocus()); }
void CACComboBox::OnSelchange() { m_wndList.ShowWindow(SW_HIDE); }

|