可编辑子项的ListCtrl

来源:互联网 发布:Win找mac共享文件 编辑:程序博客网 时间:2024/04/27 22:46

MFC提供的ListCtrl控件本身是不具备编辑子项功能的。
本文实现可以在ListCtrl中双击项Item出现编辑框和下拉列表框的编辑功能。
如下图所示:

这里写图片描述

源代码下载
示例程序下载

源代码中包含六个以下文件:
1. EditableListCtrl.h
2. EditableListCtrl.cpp
3. ListCtrlEdit.h
4. ListCtrlEdit.cpp
5. ListCtrlCombo.h
6. ListCtrlCombo.cpp

使用时,直接#include “EditableListCtrl.h”即可。


直接贴上源码:
[EditableListCtrl.h]

#pragma once#include "ListCtrlEdit.h"#include "ListCtrlCombo.h"#include <string>#include <list>#include <map>using std::string;using std::list;using std::map;// CEditableListCtrlenum ColumnCtrlType{    CCT_NONE = 0,    CCT_COMBOBOX,    CCT_EDITBOX};class CEditableListCtrl;typedef void (*EditableListCtrlItemValueUpdateAftFunc)(    CWnd* pParent,    CEditableListCtrl *pEditableListCtrl,     int iItem, int iSubItem);class CEditableListCtrl : public CListCtrl{    DECLARE_DYNAMIC(CEditableListCtrl)public:    CEditableListCtrl();    virtual ~CEditableListCtrl();protected:    DECLARE_MESSAGE_MAP()    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);    afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);    afx_msg void VScroll(UINT nSBCode, UINT nPos);    afx_msg LRESULT OnEditEnd(WPARAM wParam,LPARAM lParam);    afx_msg LRESULT OnComboEnd(WPARAM wParam,LPARAM lParam);    void ShowEdit(bool bShow, int nItem, int nSubItem, CRect rcCtrl);    void ShowCombo(bool bShow, int nItem, int nSubItem, CRect rcCtrl);public:    // 设置列控件的类型    void SetColumnCtrlType(int nColumn, ColumnCtrlType ctrlType);    // 设置列控件Combox的值    void SetColumnComboValue(int nColumn, list<string>& lstValue);    // 设置项更新后回调函数    void SetItemUpdateAftCallBackFunc(EditableListCtrlItemValueUpdateAftFunc func);private:    CListCtrlEdit m_edit;    CListCtrlCombo m_combo;    int nItem;               // 当前点击项    int nSubItem;            // 当前点击子项    bool m_bEditVisible;     // Edit是否可见    bool m_bComboVisible;    // ComboBox是否可见    map<int, ColumnCtrlType> m_Col2CtrlType;    map<int, list<string> > m_Col2ComboValue;    EditableListCtrlItemValueUpdateAftFunc m_ItemValueUpdateAftFunc;};

[EditableListCtrl.cpp]

// EditableListCtrl.cpp : implementation file//#include "stdafx.h"#include "EditableListCtrl.h"// CEditableListCtrlIMPLEMENT_DYNAMIC(CEditableListCtrl, CListCtrl)CEditableListCtrl::CEditableListCtrl() : m_bEditVisible(false), m_bComboVisible(false), nItem(-1), nSubItem(-1), m_ItemValueUpdateAftFunc(NULL){}CEditableListCtrl::~CEditableListCtrl(){}void CEditableListCtrl::SetColumnCtrlType(int nColumn, ColumnCtrlType ctrlType){    m_Col2CtrlType[nColumn] = ctrlType;}void CEditableListCtrl::SetColumnComboValue(int nColumn, list<string>& lstValue){    m_Col2ComboValue[nColumn].clear();    list<string>::iterator iterValue = lstValue.begin();    for (; iterValue != lstValue.end(); ++iterValue)    {        m_Col2ComboValue[nColumn].push_back(*iterValue);    }}void CEditableListCtrl::SetItemUpdateAftCallBackFunc(EditableListCtrlItemValueUpdateAftFunc func){    m_ItemValueUpdateAftFunc = func;}void CEditableListCtrl::ShowEdit(bool bShow, int nItem, int nSubItem, CRect rcCtrl){    if (m_edit.m_hWnd == NULL)    {        m_edit.Create(ES_AUTOHSCROLL | WS_CHILD | ES_LEFT | ES_WANTRETURN | WS_BORDER,            CRect(0,0,0,0), this, 1001);        m_edit.ShowWindow(SW_HIDE);        m_bEditVisible = false;        m_edit.SetFont(this->GetFont());    }    if (bShow == TRUE)    {        CString cstrItem = GetItemText(nItem, nSubItem);        m_edit.MoveWindow(&rcCtrl);        m_edit.ShowWindow(SW_SHOW);        m_bEditVisible = true;        m_edit.SetWindowText(cstrItem);        m_edit.SetFocus();        m_edit.SetSel(-1);     }    else    {        m_edit.ShowWindow(SW_HIDE);        m_bEditVisible = false;    }}void CEditableListCtrl::ShowCombo(bool bShow, int nItem, int nSubItem, CRect rcCtrl){    if (m_combo.m_hWnd == NULL)    {        m_combo.Create(ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_CHILD | ES_LEFT | CBS_DROPDOWNLIST,            CRect(0,0,0,0), this, 1002);        m_combo.ShowWindow(SW_HIDE);        m_bComboVisible = false;        m_combo.SetFont(this->GetFont());    }    if (bShow == TRUE && !m_Col2ComboValue[nSubItem].empty())    {        CString cstrItem = GetItemText(nItem, nSubItem);        rcCtrl.bottom += 100;        m_combo.MoveWindow(&rcCtrl);        m_combo.ShowWindow(SW_SHOW);        m_bComboVisible = true;        m_combo.SetWindowText(cstrItem);        m_combo.SetFocus();        m_combo.ResetContent();        list<string>::iterator iterValue = m_Col2ComboValue[nSubItem].begin();        for (; iterValue != m_Col2ComboValue[nSubItem].end(); ++iterValue)        {            m_combo.AddString(iterValue->c_str());        }        m_combo.SetCurSel(-1);        int nItems = m_combo.GetCount();        for (int i=0; i<nItems; ++i)        {            CString cstrItemText;            m_combo.GetLBText(i, cstrItemText);            if (cstrItem == cstrItemText)            {                m_combo.SetCurSel(i);                break;            }        }    }    else    {        m_combo.ShowWindow(SW_HIDE);        m_bComboVisible = false;    }}BEGIN_MESSAGE_MAP(CEditableListCtrl, CListCtrl)    ON_WM_LBUTTONDBLCLK()    ON_NOTIFY(HDN_BEGINTRACKA, 0, &CEditableListCtrl::OnHdnBegintrack)    ON_NOTIFY(HDN_BEGINTRACKW, 0, &CEditableListCtrl::OnHdnBegintrack)    ON_WM_HSCROLL()    ON_WM_VSCROLL()    ON_MESSAGE(WM_USER_EDIT_END, OnEditEnd)    ON_MESSAGE(WM_USER_COMBO_END, OnComboEnd)END_MESSAGE_MAP()// CEditableListCtrl message handlersLRESULT CEditableListCtrl::OnEditEnd(WPARAM wParam, LPARAM lParam){    CString strText;    m_edit.GetWindowText(strText);    SetItemText(nItem,nSubItem,strText);    if (m_ItemValueUpdateAftFunc != NULL)    {        (*m_ItemValueUpdateAftFunc)(this->GetParent(), this, nItem, nSubItem);    }    ShowEdit(false, -1, -1, CRect());    return 0;}LRESULT CEditableListCtrl::OnComboEnd(WPARAM wParam, LPARAM lParam){    int nSel = m_combo.GetCurSel();    if (nSel != -1)    {        CString cstrTextSel;        m_combo.GetLBText(nSel, cstrTextSel);        SetItemText(nItem, nSubItem, cstrTextSel);        if (m_ItemValueUpdateAftFunc != NULL)        {            (*m_ItemValueUpdateAftFunc)(this->GetParent(), this, nItem, nSubItem);        }    }    ShowCombo(false, -1, -1, CRect());    return 0;}void CEditableListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point){    // TODO: Add your message handler code here and/or call default    LVHITTESTINFO lvhti;    lvhti.pt = point;    nItem = SubItemHitTest(&lvhti);    if (nItem == -1)    {        return;    }    nSubItem = lvhti.iSubItem;    ColumnCtrlType colCtrlType = CCT_NONE;    if (m_Col2CtrlType.find(nSubItem) == m_Col2CtrlType.end())    {        return;    }    else    {        colCtrlType = m_Col2CtrlType[nSubItem];    }    CRect rcCtrl;    GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rcCtrl);    switch (colCtrlType)    {    case CCT_NONE:        break;    case CCT_EDITBOX:        ShowEdit(TRUE, nItem, nSubItem, rcCtrl);        break;    case CCT_COMBOBOX:        ShowCombo(TRUE, nItem, nSubItem, rcCtrl);        break;    default:        break;    }    CListCtrl::OnLButtonDblClk(nFlags, point);}void CEditableListCtrl::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult){    LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);    // TODO: Add your control notification handler code here    if (m_edit.m_hWnd != NULL && m_bEditVisible)        OnEditEnd(0, 0);    if (m_combo.m_hWnd != NULL && m_bComboVisible)        OnComboEnd(0, 0);    *pResult = 0;}void CEditableListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar){    // TODO: Add your message handler code here and/or call default    if (m_edit.m_hWnd != NULL && m_bEditVisible)        OnEditEnd(0, 0);    if (m_combo.m_hWnd != NULL && m_bComboVisible)        OnComboEnd(0, 0);    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);}void CEditableListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar){    // TODO: Add your message handler code here and/or call default    if (m_edit.m_hWnd != NULL && m_bEditVisible)        OnEditEnd(0, 0);    if (m_combo.m_hWnd != NULL && m_bComboVisible)        OnComboEnd(0, 0);    CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);}

[ListCtrlEdit.h]

#pragma once#define WM_USER_EDIT_END  WM_USER+101// CListCtrlEditclass CListCtrlEdit : public CEdit{    DECLARE_DYNAMIC(CListCtrlEdit)public:    CListCtrlEdit();    virtual ~CListCtrlEdit();protected:    DECLARE_MESSAGE_MAP()public:    afx_msg void OnKillFocus(CWnd* pNewWnd);    afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);};

[ListCtrlEdit.cpp]

// ListCtrlEdit.cpp : implementation file//#include "stdafx.h"#include "ListCtrlEdit.h"// CListCtrlEditIMPLEMENT_DYNAMIC(CListCtrlEdit, CEdit)CListCtrlEdit::CListCtrlEdit(){}CListCtrlEdit::~CListCtrlEdit(){}BEGIN_MESSAGE_MAP(CListCtrlEdit, CEdit)    ON_WM_KILLFOCUS()    ON_WM_MOUSEWHEEL()END_MESSAGE_MAP()// CListCtrlEdit message handlersvoid CListCtrlEdit::OnKillFocus(CWnd* pNewWnd){    CEdit::OnKillFocus(pNewWnd);    // TODO: Add your message handler code here    CWnd *pParent = this->GetParent();    ::PostMessage(pParent->GetSafeHwnd(), WM_USER_EDIT_END, 0, 0);}BOOL CListCtrlEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt){    CWnd *pParent = this->GetParent();    ::PostMessage(pParent->GetSafeHwnd(), WM_USER_EDIT_END, 0, 0);    return CWnd::OnMouseWheel(nFlags, zDelta, pt);}

[ListCtrlCombo.h]

#pragma once#define WM_USER_COMBO_END WM_USER+102// CListCtrlComboclass CListCtrlCombo : public CComboBox{    DECLARE_DYNAMIC(CListCtrlCombo)public:    CListCtrlCombo();    virtual ~CListCtrlCombo();protected:    DECLARE_MESSAGE_MAP()public:    afx_msg void OnKillFocus(CWnd* pNewWnd);};

[ListCtrlCombo.cpp]

// ListCtrlCombo.cpp : implementation file//#include "stdafx.h"#include "ListCtrlCombo.h"// CListCtrlComboIMPLEMENT_DYNAMIC(CListCtrlCombo, CComboBox)CListCtrlCombo::CListCtrlCombo(){}CListCtrlCombo::~CListCtrlCombo(){}BEGIN_MESSAGE_MAP(CListCtrlCombo, CComboBox)    ON_WM_KILLFOCUS()END_MESSAGE_MAP()// CListCtrlCombo message handlersvoid CListCtrlCombo::OnKillFocus(CWnd* pNewWnd){    CComboBox::OnKillFocus(pNewWnd);    // TODO: Add your message handler code here    CWnd *pParent = this->GetParent();    ::PostMessage(pParent->GetSafeHwnd(), WM_USER_COMBO_END, 0, 0);}
0 0