zoukankan      html  css  js  c++  java
  • WTL版本ACEdit控件,改写自MFC版,附带源码

      自动完成是个很酷也很实用的功能,比如在浏览器地址栏输入几个字母,相关的记录就会在下拉框中陈列出来。

      最近在做公司产品UI部分的改善,原版本是MFC做的,我决定用WTL,于是就遇到自动完成控件的问题。遍寻Internet,WTL版的只找到一个用IEnumString+IE组件实现的,但是其个性化修改比较困难。so我决定自己用WTL改写该控件,在此向原作者 Andreas Kapust 致谢!

      该控件包含四个文件:ACEdit.h, ACEdit.cpp, ACListWnd.h 和 ACListWnd.cpp。使用时用CACEdit 声明一个变量并将其与Edit控件或ComboBox控件建立关联(用DDX_CONTROL或者SubClassWindow)不可使用Attach,因为窗口过程函数必须要被替换。具体使用见代码。

      因为我本人也是个VC菜鸟,望有同学发现错误或不足之处能不吝指点。感谢!另外在WTL动态创建的窗口销毁上我还是不太明了,请大虾赐教!

      此为 _MODE_FIND_ALL_ 模式的效果

      

      此为 _MODE_FILESYSTEM_ 模式的效果

      

      原来不能发附件?贴下代码算了,要demo工程的邮件我 mforestlaw@163.com

    ACEdit.h

    /*************************************************************************
        Author : Andreas Kapust
        WTL Edition : Forest.Law
        Contact me at : mforestlaw@163.com
    **************************************************************************/
    #pragma once
    
    #include "ACListWnd.h"
    
    class CACEdit : public CWindowImpl<CACEdit, CEdit>,
                    public CWinDataExchange<CACEdit>,
                    public CMessageFilter {
    public:
        CACEdit();
        virtual ~CACEdit();
        virtual BOOL PreTranslateMessage(MSG* pMsg);
        
        void SetMode(int nMode = _MODE_STANDARD_);
        void SetSeparator(LPCTSTR lpszString, TCHAR lpszPrefixChar = 0);
        int  AddString(LPCTSTR lpszString);
        int  GetLBText(int nIndex, LPTSTR lpszText);
        void GetLBText(int nIndex, CString& rString);
        int  SetDroppedWidth(UINT nWidth);
        int  FindString(int nStartAfter, LPCTSTR lpszString);
        int  SelectString(int nStartAfter, LPCTSTR lpszString);
        void ShowDropDown(BOOL bShow = TRUE);
        void ResetContent();
        int  GetCurSel();
        void Init();
        void AddSearchString(LPCTSTR lpszString);
        void AddSearchStrings(LPCTSTR lpszStrings[]);
        void RemoveSearchAll();
        void SetStartDirectory(LPCTSTR lpszString);
        void SetFontHeight(long lHeight);
        void SetClearKillFocus();
    
        CACListWnd m_Liste;
    
    protected:
        BEGIN_MSG_MAP_EX(CACEdit)
            REFLECTED_COMMAND_CODE_HANDLER(EN_KILLFOCUS, OnKillFocus)
            REFLECTED_COMMAND_CODE_HANDLER(CBN_KILLFOCUS, OnKillFocus)
            MSG_WM_KEYDOWN(OnKeyDown)
            REFLECTED_COMMAND_CODE_HANDLER(EN_CHANGE, OnChange)
            REFLECTED_COMMAND_CODE_HANDLER(CBN_EDITCHANGE, OnChange)
            REFLECTED_COMMAND_CODE_HANDLER(CBN_DROPDOWN, OnCloseList)
            MSG_WM_ERASEBKGND(OnEraseBkgnd)
            MESSAGE_HANDLER(ENAC_UPDATE, OnUpdateFromList)
            MSG_WM_DESTROY(OnDestroy)
            DEFAULT_REFLECTION_HANDLER()
        END_MSG_MAP()
    
        LRESULT OnKillFocus(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled);
        void    OnKeyDown(TCHAR vkey, UINT repeats, UINT code);
        LRESULT OnChange(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled);
        LRESULT OnCloseList(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled);
        LRESULT OnEraseBkgnd(HDC hDC);
        LRESULT OnUpdateFromList(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
        void    OnDestroy();
            
        void    ReadDirectory(CString strDir);
        int        FindSepLeftPos(int nPos, bool bFindSepLeftPos = false);
        int        FindSepLeftPos2(int nPos);
        int        FindSepRightPos(int nPos);
        bool    HandleKey(UINT nChar, bool bFromChild);
    
        CString m_strEditText;
        CString m_strSeparator;
        CString m_strLastDirectory;
        TCHAR   m_prefixChar;
        int     m_nMode;
        bool    m_bCursorMode;
        int     m_nType;
        CEdit*  m_pEdit;
        TCHAR   m_szDrive[_MAX_DRIVE];
        TCHAR   m_szDir[_MAX_DIR];
        TCHAR   m_szFname[_MAX_FNAME];
        TCHAR   m_szExt[_MAX_EXT];
        CBitmap m_backBmp;
        BOOL    m_bClearTextKillFocus;
    };

    ACEdit.cpp

    #include "stdafx.h"
    #include "ACEdit.h"
    #include  <io.h>
    
    #define _EDIT_        1
    #define _COMBOBOX_    2
    
    CACEdit::CACEdit() {
        m_nMode = _MODE_STANDARD_;
        m_nType = -1;
        m_pEdit = NULL;
        m_bCursorMode = false;
        m_prefixChar = 0;
        m_bClearTextKillFocus = FALSE;
    }
    
    CACEdit::~CACEdit() {
    
    }
    
    BOOL CACEdit::PreTranslateMessage(MSG* pMsg) {
        if(pMsg->message == WM_KEYDOWN) {
            if(m_Liste.IsWindowVisible()) {
                if(m_nType == _COMBOBOX_) {
                    if(pMsg->wParam == VK_DOWN || pMsg->wParam == VK_UP) {
                        if(HandleKey(pMsg->wParam, false)) {
                            return TRUE;
                        }
                    }
                }
                if(pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN) {
                    if(HandleKey(pMsg->wParam, false)) {
                        return TRUE;
                    }
                }
            }
        }
        return FALSE;
    }
    
    void CACEdit::SetMode(int nMode) {
        if(m_nType == -1) {
            Init();
        }
        m_nMode = nMode;
    
        if(nMode == _MODE_CURSOR_O_LIST_) {
            m_nMode |= _MODE_STANDARD_;
        }
    
        if(nMode & _MODE_FILESYSTEM_) {
            m_strSeparator = _T("\");
        }
    
        if(nMode & _MODE_FIND_ALL_) {
            m_Liste.m_lMode |= _MODE_FIND_ALL_;
            SetSeparator(_T(" "));
        }
    }
    
    void CACEdit::SetSeparator(LPCTSTR lpszString,TCHAR lpszPrefixChar) {
        m_strSeparator = lpszString;
        m_Liste.m_prefixChar = m_prefixChar = lpszPrefixChar;
        SetMode(_MODE_SEPARATION_);
    }
    
    int CACEdit::AddString(LPCTSTR lpszString) {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->AddString(lpszString);
        }
        return CB_ERR;
    }
    
    int CACEdit::GetLBText(int nIndex, LPTSTR lpszText) {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->GetLBText(nIndex, lpszText);
        }
        return CB_ERR;
    }
    
    void CACEdit::GetLBText(int nIndex, CString& rString) {
        if(m_nType == _COMBOBOX_) {
            ((CComboBox*)this)->GetLBText(nIndex, rString);
        }
    }
    
    int CACEdit::SetDroppedWidth(UINT nWidth) {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->SetDroppedWidth(nWidth);
        }
        return CB_ERR;
    }
    
    int CACEdit::FindString(int nStartAfter, LPCTSTR lpszString) {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->FindString(nStartAfter, lpszString);
        }
        return CB_ERR;
    }
    
    int CACEdit::SelectString(int nStartAfter, LPCTSTR lpszString) {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->SelectString(nStartAfter, lpszString);
        }
        return CB_ERR;
    }
    
    void CACEdit::ShowDropDown(BOOL bShow) {
        if(m_nType == _COMBOBOX_) {
            ((CComboBox*)this)->ShowDropDown(bShow);
        }
    }
    
    void CACEdit::ResetContent() {
        if(m_nType == _COMBOBOX_) {
            ((CComboBox*)this)->ResetContent();
        }
    }
    
    int CACEdit::GetCurSel() {
        if(m_nType == _COMBOBOX_) {
            return ((CComboBox*)this)->GetCurSel();
        }
        return CB_ERR;
    }
    
    void CACEdit::Init() {
    //    m_backBmp.LoadBitmap(IDB_QUREY);
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        ATLASSERT(pLoop != NULL);
        pLoop->AddMessageFilter(this);
    
        WNDCLASS wndcls;
        wndcls.style = CS_CLASSDC | CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc = ::DefWindowProc;
        wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
        wndcls.hInstance = _Module.GetModuleInstance();
        wndcls.hIcon = NULL;
        wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndcls.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wndcls.lpszMenuName = NULL;
        wndcls.lpszClassName = _T("ACListWnd");
        RegisterClass(&wndcls);
    
        CRect rcWnd;
        CRect rcWnd1;
        GetWindowRect(rcWnd);
    
        HWND hListe = CreateWindowEx(WS_EX_TOOLWINDOW, 
                                     _T("ACListWnd"), 
                                     NULL,
                                     WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS | WS_OVERLAPPED, 
                                     rcWnd.left, 
                                     rcWnd.top + rcWnd.Height(),
                                     rcWnd.Width(), 
                                     rcWnd.Height(),
                                     GetDesktopWindow(), 
                                     NULL, 
                                     _Module.GetModuleInstance(), 
                                     NULL);
        ::SetWindowPos(hListe, HWND_TOPMOST, rcWnd.left, rcWnd.top + rcWnd.Height(), 
                       rcWnd.Width(), rcWnd.Height(), NULL);
        m_Liste.SubclassWindow(hListe);
    
        CString strClassName;
        ::GetClassName(this->m_hWnd, strClassName.GetBuffer(32), 32);
        strClassName.ReleaseBuffer();
    
        if (strClassName.Compare(_T("Edit")) == 0) {
            m_nType = _EDIT_;
        } else {
            if (strClassName.Compare(_T("ComboBox")) == 0) {
                m_nType = _COMBOBOX_;
                m_pEdit = (CEdit*)&GetWindow(GW_CHILD);
                ATLASSERT(m_pEdit);
                ::GetClassName(m_pEdit->m_hWnd, strClassName.GetBuffer(32), 32);
                strClassName.ReleaseBuffer();
                ATLASSERT(strClassName.Compare(_T("Edit")) == 0);
            }
        }
    
        if(m_nType == -1) {
            ATLASSERT(0);
            return;
        }
    
        m_Liste.Init(this);
    }
    
    void CACEdit::AddSearchString(LPCTSTR lpszString) {
        if(m_nType == -1) {
            ATLASSERT(0); 
            return;
        } 
        m_Liste.AddSearchString(lpszString);
    }
    
    void CACEdit::AddSearchStrings(LPCTSTR lpszStrings[]) {
        int i = 0;
        LPCTSTR str = NULL;
        if(m_nType == -1) {
            ATLASSERT(0); 
            return;
        }
        m_Liste.RemoveAll();
        do {
            str = lpszStrings[i];
            if(str) {
                m_Liste.AddSearchString(str);
            }
            i++;
        } while(str);
        m_Liste.SortSearchList();
    }
    
    void CACEdit::RemoveSearchAll() {
        if(m_nType == -1) {
            ATLASSERT(0); 
            return;
        }
        m_Liste.RemoveAll();
    }
    
    void CACEdit::SetStartDirectory(LPCTSTR lpszString) {
        if(m_nType == -1) {
            ATLASSERT(0); 
            return;
        }
        if(m_nMode & _MODE_FS_START_DIR_) {
            ReadDirectory(lpszString);
        }
    }
    
    void CACEdit::SetFontHeight(long lHeight) {
        m_Liste.SetFontHeight(lHeight);
    }
    
    void CACEdit::SetClearKillFocus() {
        m_bClearTextKillFocus = TRUE;
    }
    
    LRESULT CACEdit::OnKillFocus(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled) {
        if(m_Liste.m_hWnd) {
            m_Liste.ShowWindow(false);
        }
        if (m_bClearTextKillFocus) {
            SetWindowText(_T(""));    
            Invalidate();
        }
        return 0;
    }
    
    void CACEdit::OnKeyDown(TCHAR vkey, UINT repeats, UINT code) {
        if(!HandleKey(vkey, false)) {
            DefWindowProc();
        }
    }
    
    
    LRESULT CACEdit::OnChange(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled) {
        CString strText;
        int nPos=0;
    
        if(m_nType == -1) {
            ATLASSERT(0); 
            return 0;
        }
    
        GetWindowText(m_strEditText);
        int nLen = m_strEditText.GetLength();
    
        if(m_nMode & _MODE_FILESYSTEM_ || m_nMode & _MODE_FS_START_DIR_) {
            if(!m_bCursorMode) {
                CPoint point;
                if(m_nType == _EDIT_) {
                    GetCaretPos(&point);
                    nPos = LOWORD(((CEdit*)this)->CharFromPos(point));
                }
    
                if(m_nType == _COMBOBOX_) {
                    GetCaretPos(&point);
                    nPos = m_pEdit->CharFromPos(point);
                }
    
                if(m_nMode & _MODE_FS_START_DIR_) {
                    if(nLen) {
                        m_Liste.FindString(-1, m_strEditText);
                    } else {
                        m_Liste.ShowWindow(false);
                    }
                } else {
                    if(nLen > 2 && nPos == nLen) {            
                        if(_taccess(m_strEditText, 0) == 0) {
                            ReadDirectory(m_strEditText);
                        }
                        m_Liste.FindString(-1, m_strEditText);
                    } else {
                        m_Liste.ShowWindow(false);
                    }
                }
            }
        }
        
        if(m_nMode & _MODE_SEPARATION_) {
            if(!m_bCursorMode) {
                CPoint point;
                if(m_nType == _EDIT_) {
                    GetCaretPos(&point);
                    nPos = LOWORD(((CEdit*)this)->CharFromPos(point));
                }
    
                if(m_nType == _COMBOBOX_) {
                    GetCaretPos(&point);
                    nPos = m_pEdit->CharFromPos(point);
                }
    
                int nLeft = FindSepLeftPos(nPos - 1);
                int nRight = FindSepRightPos(nPos);
                strText = m_strEditText.Mid(nLeft, nRight - nLeft);
                m_Liste.FindString(-1, strText);
            }
        }
    
        if(m_nMode & _MODE_STANDARD_) {
            if(!m_bCursorMode) {
                m_Liste.FindString(-1, m_strEditText);
            }
        }
    
        SendMessage(ENAC_UPDATE, EN_UPDATE, GetDlgCtrlID());
        return 0;
    }
    
    LRESULT CACEdit::OnCloseList(UINT wNotifyCode, UINT wID, HWND hWndCtl, BOOL& bHandled) {
        m_Liste.ShowWindow(false);
        return 0;
    }
    
    LRESULT CACEdit::OnEraseBkgnd(HDC hDC) {
        CDC dc(hDC);     
        RECT updatarect;       
        GetClientRect(&updatarect);   
    
        CBrush BackBrush = CreatePatternBrush(m_backBmp);
        CBrush oldBrush = dc.SelectBrush(BackBrush);           
    
        CPen penBlack = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
        CPen oldPen = dc.SelectPen(penBlack);
    
        dc.Rectangle(&updatarect);     
    
        dc.SelectBrush(oldBrush);   
        dc.SelectPen(oldPen);
    
        return TRUE;
    }
    
    LRESULT CACEdit::OnUpdateFromList(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
        if(lParam == WM_KEYDOWN) {
            HandleKey(VK_DOWN, true);
        }
        return 0;
    }
    
    void CACEdit::OnDestroy() {
        m_Liste.SendMessage(WM_CLOSE);
    }
    
    void CACEdit::ReadDirectory(CString strDir) {
        if(strDir.Right(1) != _T('\')) {
            _tsplitpath_s(strDir, m_szDrive, m_szDir, m_szFname, m_szExt);
            strDir.Format(_T("%s%s"), m_szDrive, m_szDir);
        }
        TCHAR ch = (TCHAR)towupper(strDir.GetAt(0));
        strDir.SetAt(0, ch);
    
        CString m_Name, m_File, strDir1 = strDir;
        if(strDir.Right(1) != _T('\')) {
            strDir += _T("\");
        }
        if(m_strLastDirectory.CompareNoCase(strDir) == 0 && m_Liste.m_searchList.GetSize()) {
            return;
        }
        m_strLastDirectory = strDir;
        strDir += _T("*.*");
    
        WIN32_FIND_DATA findData;
        HANDLE findHandle = FindFirstFile(strDir, &findData);
        if(INVALID_HANDLE_VALUE == findHandle) {
            return;
        }
        while(FindNextFile(findHandle, &findData)) {
            m_File = findData.cFileName;
            if(findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN || 
                findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
                    continue;
            }
            if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                if(_MODE_ONLY_FILES & m_nMode) {
                    continue;
                }
                if(m_File.CompareNoCase(_T(".")) == 0 ||
                    m_File.CompareNoCase(_T("..")) == 0) {
                        continue;
                }
                if(m_File.Right(1) != _T('\')) {
                    m_File += _T("\");
                }
            } else {
                if(_MODE_ONLY_DIRS & m_nMode) {
                    continue;
                }
            }
    
            if(m_nMode & _MODE_FS_START_DIR_) {
                m_Name = m_File;
            } else {
                m_Name = strDir1;
                if(m_Name.Right(1) != _T('\')) {
                    m_Name += _T("\");
                }
                m_Name += m_File;
            }
            AddSearchString(m_Name);
        }
        FindClose(findHandle);
    }
    
    int CACEdit::FindSepLeftPos(int nPos, bool bFindSepLeftPos) {
        int nLen = m_strEditText.GetLength(); 
        TCHAR ch;
        if(nPos >= nLen && nLen != 1) {
            nPos =  nLen -1;
        }
    
        int i = nPos;
        for(; i>=0; i--) {
            ch = m_strEditText.GetAt(i);
            if(m_prefixChar == ch) {
                return i + (bFindSepLeftPos ? 1 : 0);
            }
            if(m_strSeparator.Find(ch) != -1) {
                break;
            }
        }
    
        return  i + 1;
    }
    
    int CACEdit::FindSepLeftPos2(int nPos) {
        int nLen = m_strEditText.GetLength(); 
        TCHAR ch;
    
        if(nPos >= nLen && nLen != 1) {
            nPos =  nLen - 1;
        }
    
        if(nLen == 1) {
            return 0;
        }
    
        for(int i=nPos; i>=0; i--) {
            ch = m_strEditText.GetAt(i);
            if(m_prefixChar == ch) {
                return 1;
            }
        }
    
        return  0;
    }
    
    int CACEdit::FindSepRightPos(int nPos) {
        int nLen = m_strEditText.GetLength(); 
        TCHAR ch;
    
        int i = nPos;
        for(; i<nLen; i++) {
            ch = m_strEditText.GetAt(i);
            if(m_strSeparator.Find(ch) != -1) {
                break;
            }
        }
        return i;
    }
    
    bool CACEdit::HandleKey(UINT nChar, bool bFromChild) {
        if (nChar == VK_ESCAPE || nChar == VK_RETURN) {
            m_Liste.ShowWindow(false);
            return true;
        }
    
        if (nChar == VK_DOWN || nChar == VK_UP || 
            nChar == VK_PRIOR || nChar == VK_NEXT || 
            nChar == VK_HOME || nChar == VK_END) {
            if(!m_Liste.IsWindowVisible() && (m_nMode & _MODE_CURSOR_O_LIST_)) {
                GetWindowText(m_strEditText);
                if(m_strEditText.IsEmpty()) {
                    m_Liste.CopyList();
                    return true;
                }    
            }
            if(m_Liste.IsWindowVisible()) {
                int nPos;
                if(m_nMode & _MODE_STANDARD_ || 
                   m_nMode & _MODE_FILESYSTEM_ || 
                   m_nMode & _MODE_FS_START_DIR_) {
                    m_bCursorMode = true;
                    if(!bFromChild) {
                        m_strEditText = m_Liste.GetNextString(nChar);
                    } else {
                        m_strEditText = m_Liste.GetString();
                    }
                    if(m_nMode & _MODE_FILESYSTEM_) {
                        if(m_strEditText.Right(1) == _T('\')) {
                            m_strEditText = m_strEditText.Mid(0, m_strEditText.GetLength() - 1);
                        }
                    }
    
                    m_Liste.SelectItem(-1);
                    SetWindowText(m_strEditText);
                    nPos = m_strEditText.GetLength();
                    
                    if(m_nType == _COMBOBOX_) {
                        m_pEdit->SetSel(nPos, nPos, true);
                        m_pEdit->SetModify(true);
                    }
                    if(m_nType == _EDIT_) {
                        this->SetSel(0, nPos, true);
                        this->SetModify(true);
                    }
    
                    SendMessage(ENAC_UPDATE, WM_KEYDOWN, GetDlgCtrlID());
                    m_bCursorMode = false;
                    return true;
                }
    
                if(m_nMode & _MODE_SEPARATION_) {
                    CString strText;
                    CString strLeft;
                    CString strRight;
                    int nLeft;
                    int nRight;
                    int nPos = 0;
                    int nLen;
    
                    m_bCursorMode = true;
                    GetWindowText(m_strEditText);
                    CPoint point;
                    if(m_nType == _EDIT_) {
                        GetCaretPos(&point);
                        nPos = LOWORD(((CEdit*)this)->CharFromPos(point));
                    }
    
                    if(m_nType == _COMBOBOX_) {
                        GetCaretPos(&point);
                        nPos = m_pEdit->CharFromPos(point);
                    }
                    
                    nLeft = FindSepLeftPos(nPos - 1, true);
                    nRight = FindSepRightPos(nPos);
    
                    strText = m_strEditText.Left(nLeft);
    
                    if(!bFromChild) {
                        strText += m_Liste.GetNextString(nChar);
                    } else {
                        strText += m_Liste.GetString();
                    }
                    m_Liste.SelectItem(-1);
                    strText += m_strEditText.Mid(nRight);
                    nLen = m_Liste.GetString().GetLength();
    
                    SetWindowText(strText);
                    SendMessage(ENAC_UPDATE, WM_KEYDOWN, GetDlgCtrlID());
                    
                    nRight = FindSepLeftPos2(nPos - 1);
                    nLeft -= nRight;
                    nLen += nRight;
    
                    if(m_nType == _EDIT_) {
                        ((CEdit*)this)->SetModify(true);
                        ((CEdit*)this)->SetSel(nLeft, nLeft + nLen, false);
                    }
    
                    if(m_nType == _COMBOBOX_) {
                        m_pEdit->SetModify(true);
                        m_pEdit->SetSel(nLeft, nLeft + nLen, true);
                    }
                    
                    m_bCursorMode = false;
                    return true;
                }
            }
        }
        return false;
    }

    ACListWnd.h

    #pragma once
    
    #define ENAC_UPDATE                WM_USER + 1200 
    #define IDTimerInstall             10
    #define _MAX_ENTRYS_              5
    
    #define _MODE_ONLY_FILES          (1L << 16)
    #define _MODE_ONLY_DIRS            (1L << 17)
    #define _MODE_STANDARD_            (1L << 0)
    #define _MODE_SEPARATION_         (1L << 1)
    #define _MODE_FILESYSTEM_          (1L << 2)
    #define _MODE_FS_START_DIR_        (1L << 3)
    #define _MODE_CURSOR_O_LIST_       (1L << 4)
    #define _MODE_FIND_ALL_            (1L << 5)
    #define _MODE_FS_ONLY_FILE_        (_MODE_FILESYSTEM_ | _MODE_ONLY_FILES)
    #define _MODE_FS_ONLY_DIR_         (_MODE_FILESYSTEM_ | _MODE_ONLY_DIRS)
    #define _MODE_SD_ONLY_FILE_        (_MODE_FS_START_DIR_ | _MODE_ONLY_FILES)
    #define _MODE_SD_ONLY_DIR_         (_MODE_FS_START_DIR_ | _MODE_ONLY_DIRS)
    
    class CACListWnd : public CWindowImpl<CACListWnd> {
    public:
        CACListWnd();
        virtual ~CACListWnd();
    
        void    Init(CWindow* pWindow);
        bool    EnsureVisible(int nItem, bool bWait);
        bool    SelectItem(int nItem);
        int     FindString(int nStartAfter, LPCTSTR lpszString, bool bDisplayOnly = false);
        int     FindStringExact(int nIndexStart, LPCTSTR lpszFind);
        int     SelectString(LPCTSTR lpszString);
        bool    GetText(int nItem, CString& strText);
        void    AddSearchString(LPCTSTR lpszString);
        void    RemoveAll();
        CString GetString();
        CString GetNextString(int nChar);
        void    CopyList();
        void    SortSearchList();
        void    DrawItem(CDC* pDC, long lItem, long lWidth);
        void    SetFontHeight(long lHeight);
        
        CString m_strDisplay;
        TCHAR   m_prefixChar;
        long    m_lMode;
        long    m_lFontHeight;
        CSimpleArray<CString> m_searchList;
    
    protected:
        BEGIN_MSG_MAP_EX(CACListWnd)
            MSG_WM_PAINT(OnPaint)
            MSG_WM_SIZE(OnSize)
            MSG_WM_ERASEBKGND(OnEraseBkgnd)
            MSG_WM_NCPAINT(OnNcPaint)
            MSG_WM_KEYDOWN(OnKeyDown)
            MSG_WM_NCCALCSIZE(OnNcCalcSize)
            MSG_WM_VSCROLL(OnVScroll)
            MSG_WM_ACTIVATEAPP(OnActivateApp)
            MSG_WM_NCHITTEST(OnNcHitTest)
            MSG_WM_LBUTTONDOWN(OnLButtonDown)
            MSG_WM_RBUTTONDOWN(OnRButtonDown)
            MSG_WM_SETCURSOR(OnSetCursor)
            MSG_WM_SHOWWINDOW(OnShowWindow)
            MSG_WM_NCLBUTTONDOWN(OnNcLButtonDown)
            MSG_WM_MOUSEMOVE(OnMouseMove)
            MSG_WM_TIMER(OnTimer)
            MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
        END_MSG_MAP()
    
        void    OnPaint(HDC hDC);
        void    OnSize(UINT nType, CSize size);
        LRESULT OnEraseBkgnd(HDC hDC);
        void    OnNcPaint(HRGN hRgn);
        void    OnKeyDown(TCHAR vkey, UINT repeats, UINT code);
        LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam);
        void    OnVScroll(int nSBCode, short nPos, HWND hWnd);
        void    OnActivateApp(BOOL bActive, DWORD dwThreadID);
        LRESULT OnNcHitTest(CPoint point);
        void    OnLButtonDown(UINT nFlags, CPoint point);
        void    OnRButtonDown(UINT nFlags, CPoint point);
        LRESULT OnSetCursor(HWND hWnd, UINT nHitTest, UINT nMessage);
        void    OnShowWindow(BOOL bShow, int nStatus);
        void    OnNcLButtonDown(UINT nHitTest, CPoint point);
        void    OnMouseMove(UINT nFlags, CPoint point);
        void    OnTimer(UINT nIDEvent);
        void    OnGetMinMaxInfo(LPMINMAXINFO lpMMI);
    
        int     HitTest(CPoint point);
        void    SetScroller();
        void    SetProp();
        long    ScrollBarWidth();
        void    InvalidateAndScroll();
        void    SortList(CSimpleArray<CString>& List);
        static int CompareString(const void* p1, const void* p2);
    
        CScrollBar m_vertBar;
        CScrollBar m_horzBar;
        CRect      m_lastSize;
        CRect      m_parentRect;
        CEdit*     m_pEdit;
        int        m_nIDTimer;
        long       m_lTopIndex;
        long       m_lCount;
        long       m_lItemHeight;
        long       m_lVisibleItems;
        long       m_lSelItem;
        CSimpleArray<CString> m_displayList;
    };

    ACListWnd.cpp

    #include "stdafx.h"
    #include "ACListWnd.h"
    
    void DoPaintMessageLoop() {
        MSG msg;
        while(::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
    }
    
    CACListWnd::CACListWnd() {
        m_lTopIndex = 0;
        m_lCount = 0;
        m_lItemHeight = 16;
        m_lSelItem = -1;
        m_lVisibleItems = 0;
        m_pEdit = NULL;
        m_lastSize.SetRectEmpty();
        m_prefixChar = 0;
        m_lMode = 0;
        m_lFontHeight = 0;
    }
    
    CACListWnd::~CACListWnd() {
        m_searchList.RemoveAll();
        m_displayList.RemoveAll();
    }
    
    void CACListWnd::Init(CWindow* pWindow) {
        ATLASSERT(m_vertBar.Create(this->m_hWnd, 
                                   CRect(0, 0, GetSystemMetrics(SM_CYVSCROLL), 100),
                                   NULL, 
                                   WS_CHILD | WS_VISIBLE|SBS_VERT|SBS_LEFTALIGN,
                                   NULL));
    
        SetScroller();
        m_pEdit = (CEdit*)pWindow;
        m_lCount = m_displayList.GetSize();
        m_vertBar.SetScrollPos(0, false);
        SetProp();
    
        CDC dc(GetDC());
        LOGFONT logFont = {0};
        CFont((HFONT)GetStockObject(DEFAULT_GUI_FONT)).GetLogFont(&logFont);
    
        if (m_lFontHeight > 0) {
            logFont.lfHeight = m_lFontHeight;
            logFont.lfWeight = FW_BOLD;
            dc.SelectFont(CreateFontIndirect(&logFont));
        }
    
        m_lItemHeight = abs(logFont.lfHeight);
    }
    
    bool CACListWnd::EnsureVisible(int nItem, bool bWait) {
        if(nItem > m_lTopIndex && nItem < m_lTopIndex + m_lVisibleItems) {
            return false;
        }
    
        if(nItem > m_lTopIndex) {
            int nLen = nItem;
            for(int i=m_lTopIndex; i<nLen; i++) {
                if(i >= m_lCount - m_lVisibleItems || i + m_lVisibleItems > nItem) {
                    break;
                }
                m_lTopIndex++;
                if(bWait) {
                    InvalidateAndScroll();
                    Sleep(10);
                    DoPaintMessageLoop();
                }
            }
            InvalidateAndScroll();
            return true;
        }
    
        if(nItem < m_lTopIndex) {
            while(nItem < m_lTopIndex) {
                if(m_lTopIndex > 0) {
                    m_lTopIndex--;
                } else {
                    break;
                }
                if(bWait) {
                    InvalidateAndScroll();
                    Sleep(10);
                    DoPaintMessageLoop();
                }
            }
            InvalidateAndScroll();
            return true;
        }
        return false;
    }
    
    bool CACListWnd::SelectItem(int nItem) {
        if(nItem > m_lCount) {
            return false;
        }
        if(nItem == -1) {
            EnsureVisible(m_lSelItem, false);
            Invalidate();
            return false;
        }
        m_lSelItem = nItem;
        if(!EnsureVisible(nItem,true)) {
            Invalidate();
        }
        return true;
    }
    
    int CACListWnd::FindString(int nStartAfter, LPCTSTR lpszString, bool bDisplayOnly) {
        long lCount = m_displayList.GetSize();
        if(!bDisplayOnly) {
            CString str1;
            CString str2(lpszString);
            if(!m_pEdit) {
                ShowWindow(false);
                return -1;
            }
            if(nStartAfter > m_searchList.GetSize()) {
                ShowWindow(false);
                return -1;
            }
            if(str2.IsEmpty()) {
                ShowWindow(false);
                return -1;
            }
            m_displayList.RemoveAll();
            str2.MakeUpper();
            for(int i=nStartAfter + 1; i<m_searchList.GetSize(); i++) {
                if(m_prefixChar) {
                    str1 = m_prefixChar;
                } else {
                    str1 = _T("");
                }
                str1 += m_searchList[i];
                str1.MakeUpper();
                if(m_lMode & _MODE_FIND_ALL_) {
                    if(str1.Find(str2) >= 0) {
                        m_displayList.Add(m_searchList[i]);
                    }
                } else {
                    if(str1.Find(str2) == 0) {
                        m_displayList.Add(m_searchList[i]);
                    }
                }
            }
        }
    
        m_lCount = m_displayList.GetSize();
        if(m_lCount) {
            CRect rcWnd;
            int nWidth;
            m_pEdit->GetWindowRect(rcWnd);
            
            SetScroller();
            SetProp();
            ShowWindow(true);
            Invalidate();
    
            int nHeight = m_lCount * m_lItemHeight + 2 * GetSystemMetrics(SM_CYBORDER);
            if(m_lCount > _MAX_ENTRYS_) {
                nHeight = _MAX_ENTRYS_ * m_lItemHeight + 2 * GetSystemMetrics(SM_CYBORDER);
            }
    
            if(!m_lastSize.IsRectEmpty()) {
                nWidth = m_lastSize.Width(); 
                nHeight = m_lastSize.Height(); 
                rcWnd.top += rcWnd.Height();
                rcWnd.right = rcWnd.left + nWidth;
                rcWnd.bottom = rcWnd.top + nHeight;
                MoveWindow(rcWnd.left, rcWnd.top, rcWnd.Width(), rcWnd.Height());
            } else {
                MoveWindow(rcWnd.left, rcWnd.top + rcWnd.Height(), rcWnd.Width(), nHeight);
            }
    
            if(lCount != m_displayList.GetSize()) {
                m_lSelItem = -1;
            }
            SortList(m_displayList);
        } else {
            ShowWindow(false);
        }
        return 1;
    }
    
    int CACListWnd::FindStringExact(int nIndexStart, LPCTSTR lpszFind) {
        if(nIndexStart > m_searchList.GetSize()) {
            return -1;
        }
        for(int i=nIndexStart + 1; i<m_searchList.GetSize(); i++) {
            if(m_searchList[i].Compare(lpszFind) == 0) {
                return i;
            }
        }
        return -1;
    }
    
    int CACListWnd::SelectString(LPCTSTR lpszString) {
        int nItem = FindString(-1, lpszString);
        SelectItem(nItem);
        return nItem;
    }
    
    bool CACListWnd::GetText(int nItem, CString& strText) {
        if(nItem < 0 || nItem > m_searchList.GetSize()) {
            return false;
        }
        strText = m_searchList[nItem];
        return true;
    }
    
    void CACListWnd::AddSearchString(LPCTSTR lpszString) {
        m_searchList.Add(lpszString);
    }
    
    void CACListWnd::RemoveAll() {
        m_searchList.RemoveAll();
        m_displayList.RemoveAll();
    }
    
    CString CACListWnd::GetString() {
        int i = m_displayList.GetSize();
        if(i == 0) {
            return _T("");
        }
        if(i <= m_lSelItem || m_lSelItem == -1) {
            i = 0;
        } else {
            i = m_lSelItem;
        }
        return m_displayList[i];
    }
    
    CString CACListWnd::GetNextString(int nChar) {
        switch(nChar) {
        case VK_DOWN: 
            m_lSelItem++; 
            break;
        case VK_UP: 
            m_lSelItem--; 
            break;
        case VK_PRIOR:
            m_lSelItem -= m_lVisibleItems;
            if(m_lSelItem < 0) {
                m_lSelItem = 0;
            }
            break;
        case VK_NEXT:
            m_lSelItem += m_lVisibleItems;
            if(m_lSelItem >= m_lCount - 1) {
                m_lSelItem = m_lCount - 1;
            }
            break;
        case VK_HOME:
            m_lSelItem = 0;
            break;
        case VK_END:
            m_lSelItem = m_lCount - 1;
            break;
        }
    
        if(m_lSelItem < 0) {
            m_lSelItem = m_lCount - 1;
        }
        if(m_lSelItem >= m_lCount) {
            m_lSelItem = 0;
        }
        if(EnsureVisible(m_lSelItem, m_lCount > 50 ? false : true)) {
            InvalidateAndScroll();
        }
        return GetString();
    }
    
    void CACListWnd::CopyList() {
        m_displayList = m_searchList;
        m_lCount = m_displayList.GetSize();
        if(m_lCount) {
            FindString(0, _T(""), true);
        }
    }
    
    void CACListWnd::SortSearchList() {
        SortList(m_searchList);
    }
    
    void CACListWnd::DrawItem(CDC* pDC, long lItem, long lWidth) {
        long y = lItem - m_lTopIndex;
        CRect rcLabel(2, y * m_lItemHeight, lWidth, (y + 1) * m_lItemHeight);
        pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
        if(lItem == m_lSelItem) {
            rcLabel.left = 0;
            pDC->FillSolidRect(rcLabel, ::GetSysColor(COLOR_HIGHLIGHT));
            pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
            rcLabel.left = 2;
        }
        if(m_prefixChar) {
            m_strDisplay = m_prefixChar + m_displayList[lItem];
        } else {
            m_strDisplay = m_displayList[lItem];
        }
        pDC->DrawText(m_strDisplay, -1, rcLabel, DT_LEFT | DT_SINGLELINE | 
                      DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS);
    }
    
    void CACListWnd::SetFontHeight(long lHeight) {
        m_lFontHeight = lHeight;
    }
    
    void CACListWnd::OnPaint(HDC hDC) {
        CRect rcWnd;
        CRect rect;
        CRect rc;
        CDC* pDC = NULL;
    
        GetClientRect(rc);
        rcWnd = rect = rc;
    
        rc.left = rc.right - GetSystemMetrics(SM_CXHSCROLL);
        rc.top = rc.bottom - GetSystemMetrics(SM_CYVSCROLL);
    
        rect.right -= ScrollBarWidth();
        
        CPaintDC dc(this->m_hWnd);
        CDC MemDC = CreateCompatibleDC(dc);
    
        CBitmap bitmap = CreateCompatibleBitmap(dc, rect.Width(), rect.Height());
        CBitmap oldBitmap = MemDC.SelectBitmap(bitmap);
    
        MemDC.SetWindowOrg(rect.left, rect.top);
    
        long lWidth = rcWnd.Width() - ScrollBarWidth();
    
        MemDC.FillSolidRect(rcWnd, ::GetSysColor(COLOR_WINDOW));
        
        int i = 0;
        if (m_lFontHeight <= 0) {
            MemDC.SelectFont((HFONT)GetStockObject(DEFAULT_GUI_FONT)); 
            MemDC.SetBkMode(TRANSPARENT);
            for(i=m_lTopIndex; i<m_lCount; i++) {
                DrawItem(&MemDC, i, lWidth);
            }
        } else {        
            LOGFONT logFont = {0};
            CFont((HFONT)GetStockObject(DEFAULT_GUI_FONT)).GetLogFont(&logFont);
            logFont.lfHeight = m_lFontHeight;
            logFont.lfWeight =  FW_BOLD;
            logFont.lfItalic = TRUE;
            CFont font = CreateFontIndirect(&logFont);
            CFont oldFont = MemDC.SelectFont(font);
            MemDC.SetBkMode(TRANSPARENT);
            for(i=m_lTopIndex; i<m_lCount; i++) {
                DrawItem(&MemDC, i, lWidth);
            }
            MemDC.SelectFont(oldFont);
        }
    
        CPen pen1 = CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOW));
        CPen pen2 = CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNFACE));
        CPen pen3 = CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
    
        pDC = &dc;
        if(m_vertBar.IsWindowVisible()) {
            dc.FillSolidRect(rc, ::GetSysColor(COLOR_BTNFACE));
        } else {
            pDC = &MemDC;
        }
    
        CPen oldPen = pDC->SelectPen(pen1);
        int nBottom= rcWnd.bottom - GetSystemMetrics(SM_CXHSCROLL) - 1;
        lWidth = GetSystemMetrics(SM_CXHSCROLL);
    
        int a = 1;
        for(i=0; i<20; i++, a++) {
            if(a == 1) {
                pDC->SelectPen(pen1);
            } else if(a == 2) {
                pDC->SelectPen(pen2);
            } else if(a == 3) {
                pDC->SelectPen(pen3);
            } else {
                a = 0;
            }
            pDC->MoveTo(rc.left + i - 1, rcWnd.bottom);
            pDC->LineTo(rc.left + i + lWidth, nBottom);
        }
        dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), MemDC, 
                  rect.left, rect.top, SRCCOPY);
        pDC->SelectPen(oldPen);
        MemDC.SelectBitmap(oldBitmap);
    }
    
    void CACListWnd::OnSize(UINT nType, CSize size) {
        SetScroller();
        SetProp();
        if(!m_lastSize.IsRectEmpty()) {
            GetWindowRect(m_lastSize);
        }
    }
    
    LRESULT CACListWnd::OnEraseBkgnd(HDC hDC) {
        return 0;
    }
    
    void CACListWnd::OnNcPaint(HRGN hRgn) {
        CWindowDC dc(this->m_hWnd);
        CRect rectClient;
        CRect rectWindow;
        CRect rcWnd;
        GetClientRect(rectClient);
        GetWindowRect(rectWindow);
        ScreenToClient(rectWindow);
    
        rectClient.OffsetRect(-(rectWindow.left), -(rectWindow.top));
        dc.ExcludeClipRect(rectClient);
    
        rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);
    
        dc.FillSolidRect(rectWindow, ::GetSysColor(COLOR_WINDOWTEXT));
    }
    
    void CACListWnd::OnKeyDown(TCHAR vkey, UINT repeats, UINT code) {
        if (vkey == VK_ESCAPE) {
            ShowWindow(false);
        }
    }
    
    LRESULT CACListWnd::OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam) {
        NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)lParam;
        return ::InflateRect(lpncsp->rgrc, -GetSystemMetrics(SM_CXBORDER),
                             -GetSystemMetrics(SM_CYBORDER));
    }
    
    void CACListWnd::OnVScroll(int nSBCode, short nPos, HWND hWnd) {
        long lOldTopIndex = m_lTopIndex;
        switch(nSBCode) {
        case SB_ENDSCROLL:
            break;
        case SB_PAGEUP:
            m_lTopIndex -= m_lVisibleItems;
            if(m_lTopIndex < 0) {
                m_lTopIndex = 0;
            }
            break;
        case SB_PAGEDOWN:
            m_lTopIndex += m_lVisibleItems;
            if(m_lTopIndex >= m_lCount - m_lVisibleItems) {
                m_lTopIndex = m_lCount-m_lVisibleItems;
            }
            break;
        case SB_LINEUP:
            m_lTopIndex--;
            if(m_lTopIndex < 0) {
                m_lTopIndex = 0;
            }
            break;
        case SB_LINEDOWN:
            m_lTopIndex++;
            if(m_lTopIndex >= m_lCount - m_lVisibleItems) {
                m_lTopIndex = m_lCount - m_lVisibleItems;
            }
            break;
        case SB_THUMBTRACK:
            m_lTopIndex = nPos;
            break;
        }
    
        m_vertBar.SetScrollPos(m_lTopIndex, true);
    
        if(lOldTopIndex != m_lTopIndex) {
            Invalidate();
        }
    }
    
    void CACListWnd::OnActivateApp(BOOL bActive, DWORD dwThreadID) {
        ShowWindow(false);
    }
    
    LRESULT CACListWnd::OnNcHitTest(CPoint point) {
        CRect rectClient;
        GetWindowRect(rectClient);
        rectClient.left = rectClient.right - GetSystemMetrics(SM_CYVSCROLL);
        rectClient.top = rectClient.bottom - GetSystemMetrics(SM_CXVSCROLL);
        if(rectClient.PtInRect(point)) {
            return HTBOTTOMRIGHT;
        } else {
            return HTCLIENT;
        }
    }
    
    void CACListWnd::OnLButtonDown(UINT nFlags, CPoint point) {
        int nSel = HitTest(point);
        if(nSel >= 0) {
            if(!EnsureVisible(nSel, true)) {
                Invalidate();
            }
            m_lSelItem = nSel;
            m_pEdit->SendMessage(ENAC_UPDATE, GetDlgCtrlID(), WM_KEYDOWN);
            DoPaintMessageLoop();
            Sleep(100);
            ShowWindow(false);
        } else {
            CRect rect;
            GetClientRect(rect);
            if(!rect.PtInRect(point)) {
                ShowWindow(false);
            }
        }
    }
    
    void CACListWnd::OnRButtonDown(UINT nFlags, CPoint point) {
        ShowWindow(false);
    }
    
    LRESULT CACListWnd::OnSetCursor(HWND hWnd, UINT nHitTest, UINT nMessage) {
        CRect rectClient;
        GetWindowRect(rectClient);
        ScreenToClient(&rectClient);
    
        rectClient.left = rectClient.right - GetSystemMetrics(SM_CYVSCROLL);
        rectClient.top = rectClient.bottom - GetSystemMetrics(SM_CXVSCROLL);
    
        CPoint ptCursor;
        GetCursorPos(&ptCursor);
        ScreenToClient(&ptCursor);
    
        SetCursor(LoadCursor(NULL, IDC_ARROW));
        return TRUE;
    }
    
    void CACListWnd::OnShowWindow(BOOL bShow, int nStatus) {
        if(bShow) {
            m_nIDTimer = SetTimer(IDTimerInstall, 200, NULL);
            m_pEdit->GetParent().GetWindowRect(m_parentRect);
        } else {
            if(m_nIDTimer) {
                KillTimer(IDTimerInstall);
            }
            m_nIDTimer = 0;
            m_lSelItem = -1;
            m_lTopIndex = 0;
        }
    }
    
    void CACListWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) {
        if(OnNcHitTest(point) == HTBOTTOMRIGHT) {
            GetWindowRect(m_lastSize);
        }
    }
    
    void CACListWnd::OnMouseMove(UINT nFlags, CPoint point) {
        int nSel = HitTest(point);
        if(nSel >= 0) {
            Invalidate();
        }
    }
    
    void CACListWnd::OnTimer(UINT nIDEvent) {
        CRect parentRect;
        switch(nIDEvent) {
        case IDTimerInstall:
            m_pEdit->GetParent().GetWindowRect(parentRect);
            if(!parentRect.EqualRect(m_parentRect)) {
                ShowWindow(false);
            }
            break;
        default:
            break;
        }
    }
    
    void CACListWnd::OnGetMinMaxInfo(LPMINMAXINFO lpMMI) {
        if(this->m_hWnd) {
            long lMinY1 = 2 * GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXHTHUMB);
            long lMinY2 = m_lCount * m_lItemHeight + 2 * GetSystemMetrics(SM_CYBORDER);
            if(m_lVisibleItems > m_lCount - 1 &&  lMinY2 < lMinY1) {
                lpMMI->ptMinTrackSize.y = lMinY2;
            } else {
                lpMMI->ptMinTrackSize.y = lMinY1;
            }
    
            lpMMI->ptMinTrackSize.x = 4 * GetSystemMetrics(SM_CXHSCROLL);
    
            if(m_pEdit != NULL) {
                RECT rect;
                m_pEdit->GetWindowRect(&rect);
                lpMMI->ptMinTrackSize.x = rect.right - rect.left;
            }
        }
    }
    
    int CACListWnd::HitTest(CPoint point) {
        CRect rcItem;
        CRect rcWnd;
    
        GetClientRect(rcWnd);
        long lWidth = rcWnd.Width() - ScrollBarWidth();
    
        for(int i=m_lTopIndex; i<m_lCount; i++) {
            long y = i - m_lTopIndex;
            rcItem.SetRect(2, y * m_lItemHeight, lWidth, (y + 1) * m_lItemHeight);
            if(PtInRect(&rcItem, point)) {
                return m_lSelItem = (y + m_lTopIndex);
            }
        }
        return -1;
    }
    
    void CACListWnd::SetScroller() {
        CRect rcWnd;
        CRect rcBar;
        GetClientRect(rcWnd);
        if(m_vertBar.m_hWnd) {
            rcBar = rcWnd;
            rcBar.top = -1;
            rcBar.left = rcWnd.Width() - GetSystemMetrics(SM_CYVSCROLL);
            rcBar.bottom -= GetSystemMetrics(SM_CYHSCROLL);
            m_vertBar.MoveWindow(rcBar);
            rcBar.top = rcWnd.bottom - 20;
            rcBar.bottom = rcWnd.bottom;
            m_vertBar.SetScrollPos(m_lTopIndex, true);    
        }
    }
    
    void CACListWnd::SetProp() {
        CRect rcWnd;
        CRect rcBar;
    
        if(!m_lCount) {
            return;
        }
    
        GetWindowRect(rcWnd);
        ScreenToClient(rcWnd);
    
        SCROLLINFO si;
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask =  SIF_PAGE | SIF_RANGE;
        si.nMin = 0;
        si.nMax =  m_lCount - 1;
        m_lVisibleItems = si.nPage = rcWnd.Height() / m_lItemHeight;
        si.nTrackPos = 2;
        m_vertBar.SetScrollRange(0, m_lCount - 1);
        m_vertBar.SetScrollInfo(&si);
        if(m_lVisibleItems > m_lCount - 1) {
            m_vertBar.ShowWindow(false);
        } else {
            m_vertBar.ShowWindow(true);
        }
    
        if(m_lTopIndex + m_lVisibleItems > m_lCount) {
            m_lTopIndex = m_lCount - m_lVisibleItems;
            if(m_lTopIndex < 0) {
                m_lTopIndex = 0;
            }
            m_vertBar.SetScrollPos(m_lTopIndex, true);
        }
    }
    
    long CACListWnd::ScrollBarWidth() {
        if(m_vertBar.IsWindowVisible()) {
            return GetSystemMetrics(SM_CYVSCROLL);
        } else {
            return 0;
        }
    }
    
    void CACListWnd::InvalidateAndScroll() {
        m_vertBar.SetScrollPos(m_lTopIndex, true);
        Invalidate();
        DoPaintMessageLoop();
    }
    
    void CACListWnd::SortList(CSimpleArray<CString>& List) {
        int nCount = List.GetSize();    
        if (nCount > 1) {
            CSimpleArray<CString> List2 = List;
            LPCTSTR* ppSortArray = new LPCTSTR[nCount + 1];
            int i=0;
            for(; i<nCount; i++) {
                ppSortArray[i] = (LPCTSTR)List2[i];
            }        
            List.RemoveAll();
            qsort(ppSortArray, nCount, sizeof(LPCTSTR), CompareString);
    
            for(i=0; i<nCount; i++) {
                List.Add((LPCTSTR)ppSortArray[i]);
            }
            List2.RemoveAll();
            delete[] ppSortArray;
        }
    }
    
    int CACListWnd::CompareString(const void* p1, const void* p2) {
        return _stricmp(*(char**)p1, *(char**)p2);
    }
  • 相关阅读:
    javascript对象继承的实现
    浏览器兼容问题汇总<转>
    DOM笔记
    Ajax日记
    学习态度
    项目1
    导航项目-整体布局
    有关布局
    导航项目开始
    windows 服务 定时程序 跑不出数据
  • 原文地址:https://www.cnblogs.com/mforestlaw/p/WTLACEdit.html
Copyright © 2011-2022 走看看