说明
在上一篇文章:可编辑子项的ListCtrl
我们实现了一个简易版本的可编辑子项的ListCtrl。
本文我们继续增加一个功能,即在ListCtrl中,实现可以直接输入内容的ComboBox。
所以,ListCtrl会存在以下三种可编辑项。
1、可编辑的文本框。
2、ComboBox
3、可直接输入内容的ComboBox。
下载
- ListCtrlXE.h
- ListCtrlXE.cpp
- EditLCXE.h
- EditLCXE.cpp
- ComboLCXE.h
- ComboLCXE.cpp
- EditInComboLCXE.h
- EditInComboLCXE.cpp
使用时,直接#include “ListCtrlXE.h”即可。
部分源码
[ListCtrlXE.h]
#pragma once
#include ".\LCXE\EditLCXE.h"
#include ".\LCXE\ComboLCXE.h"
#include <string>
#include <list>
#include <map>
using std::string;
using std::list;
using std::map;
// 双击客制化消息,在双击控件时会向父窗口发送该消息
// 该消息的WPARAM与LPARAM均为LCXE_LBDC_Data的指针
#define MSG_LCXE_LBTN_DBLCLICK_CUSTOM WM_USER + 0x111
// ComboBox结束消息
// 该消息的WPARAM与LPARAM均为LCXE_ComboEndData的指针
#define MSG_LCXE_COMBO_END WM_USER + 0x112
// EditBox结束消息
// 该消息的WPARAM与LPARAM均为LCXE_EditEndData的指针
#define MSG_LCXE_EDIT_END WM_USER + 0x113
class CListCtrlXE;
// ListCtrlXE Left Button Double Click Data
struct LCXE_LBDC_Data
{
int nItem;
int nSubItem;
CListCtrlXE* pLCXE;
};
// ListCtrlXE ComboBox End Msg Data
struct LCXE_ComboEndData
{
int nItem;
int nSubItem;
CComboBox* pCombo;
CListCtrlXE* pLCXE;
};
// ListCtrlXE Edit End Msg Data
struct LCXE_EditEndData
{
int nItem;
int nSubItem;
CEdit* pEdit;
CListCtrlXE* pLCXE;
};
class CListCtrlXE : public CListCtrl
{
DECLARE_DYNAMIC(CListCtrlXE)
public:
CListCtrlXE();
virtual ~CListCtrlXE();
protected:
DECLARE_MESSAGE_MAP()
protected:
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 LRESULT OnEditEnd(WPARAM wParam,LPARAM lParam);
afx_msg LRESULT OnComboEnd(WPARAM wParam,LPARAM lParam);
// 显示EditBox
int ShowEditBox(CEditLCXE* pEdit, bool bShow);
// 显示ComboBox
int ShowCombo(CComboLCXE* pCombo, bool bShow);
public:
// 创建EditBox
// 注意:请勿对返回的CEdit*执行delete操作
CEdit* CreateEdit(DWORD dwStyle = ES_AUTOHSCROLL | ES_LEFT | ES_WANTRETURN | WS_BORDER);
// 创建ComboBox
// 注意:请勿对返回的CComboBox*执行delete操作
CComboBox* CreateCombo(DWORD dwStyle = ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | CBS_DROPDOWNLIST);
// 显示EditBox
int ShowEditBox(CEdit* pEdit);
// 显示ComboBox
int ShowCombo(CComboBox* pCombo);
private:
// 子控件列表
list<CEditLCXE*> m_lstEdit;
list<CComboLCXE*> m_lstCombo;
// 当前点击项
int nItem;
// 当前点击子项
int nSubItem;
// 子控件ID
int m_nCtrlId;
};
[ListCtrlXE.cpp]
// EditableListCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "ListCtrlXE.h"
// CListCtrlXE
IMPLEMENT_DYNAMIC(CListCtrlXE, CListCtrl)
CListCtrlXE::CListCtrlXE()
{
m_nCtrlId = 1001;
}
CListCtrlXE::~CListCtrlXE()
{
list<CEditLCXE*>::iterator iterEdit = m_lstEdit.begin();
for (; iterEdit != m_lstEdit.end(); ++iterEdit)
{
CEditLCXE* pEdit = *iterEdit;
delete pEdit;
}
list<CComboLCXE*>::iterator iterCombo = m_lstCombo.begin();
for (; iterCombo != m_lstCombo.end(); ++iterCombo)
{
CComboLCXE* pCombo = *iterCombo;
delete pCombo;
}
}
//-----------------------------------------------------------------------------
// 函数: CreateEdit
// 功能: 创建Edit
// 参数:
// dwStyle ------ Edit的风格,默认的风格为ES_AUTOHSCROLL | ES_LEFT | ES_WANTRETURN | WS_BORDER
// 返回值:
// CEdit* ------ 创建的Edit的指针,创建失败则返回NULL
// 注意:
// 创建的Edit由程序内部进行资源管理,请勿对返回的指针执行delete,DestroyWindow等操作
//-----------------------------------------------------------------------------
CEdit* CListCtrlXE::CreateEdit(DWORD dwStyle)
{
CEditLCXE* pEdit = new CEditLCXE();
if (0 == pEdit->Create(dwStyle | WS_CHILD, CRect(0, 0, 0, 0), this, m_nCtrlId++))
{
return NULL;
}
pEdit->ShowWindow(SW_HIDE);
pEdit->SetFont(this->GetFont());
m_lstEdit.push_back(pEdit);
return pEdit;
}
//-----------------------------------------------------------------------------
// 函数: CreateCombo
// 功能: 创建ComboBox
// 参数:
// dwStyle ------ ComboBox的风格,默认的风格为ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | CBS_DROPDOWNLIST
// 返回值:
// CComboBox* ------ 创建的ComboBox的指针,创建失败则返回NULL
// 注意:
// 1.创建的ComboBox由程序内部进行资源管理,请勿对返回的指针执行delete,DestroyWindow等操作
// 2.可创建CBS_DROPDOWN风格的ComboBox
//-----------------------------------------------------------------------------
CComboBox* CListCtrlXE::CreateCombo(DWORD dwStyle)
{
CComboLCXE *pCombo = new CComboLCXE();
if (0 == pCombo->Create(dwStyle | WS_CHILD, CRect(0,0,0,0), this, m_nCtrlId++))
{
return NULL;
}
pCombo->ShowWindow(SW_HIDE);
pCombo->SetFont(this->GetFont());
m_lstCombo.push_back(pCombo);
return pCombo;
}
// 显示EditBox
int CListCtrlXE::ShowEditBox(CEditLCXE* pEdit, bool bShow)
{
if (NULL == pEdit)
{
return -1;
}
if (true == bShow)
{
if (nItem == -1 || nSubItem == -1)
{
return -1;
}
CString cstrText = this->GetItemText(nItem, nSubItem);
CRect rcCtrl(0, 0, 0, 0);
this->GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rcCtrl);
pEdit->MoveWindow(&rcCtrl);
pEdit->ShowWindow(SW_SHOW);
pEdit->SetWindowText(cstrText);
pEdit->SetFocus();
pEdit->SetSel(-1);
}
else
{
pEdit->ShowWindow(SW_HIDE);
}
return 0;
}
//---------------------------------------------------------
// 函数: ShowEditBox
// 功能: 显示EditBox
// 参数:
// pEdit ------ 待显示的EditBox的指针,该EditBox必须为调用CListCtrlXE::CreateEdit创建,
// 否则将不会显示,并且函数返回-1
// 返回值:
// 0 ------ 成功
// -1 ------ 失败
//---------------------------------------------------------
int CListCtrlXE::ShowEditBox(CEdit* pEdit)
{
if (NULL == pEdit)
{
return -1;
}
// 校验pEdit是否由调用CreateEdit创建的
bool bFind = false;
list<CEditLCXE*>::iterator iterEdit = m_lstEdit.begin();
for (; iterEdit != m_lstEdit.end(); ++iterEdit)
{
if (*iterEdit == (CEditLCXE*)pEdit)
{
bFind = true;
break;
}
}
if (false == bFind)
{
return -1;
}
// 显示
return this->ShowEditBox((CEditLCXE*)pEdit, true);
}
// 显示ComboBox
int CListCtrlXE::ShowCombo(CComboLCXE* pCombo, bool bShow)
{
if (NULL == pCombo)
{
return -1;
}
if (true == bShow)
{
if (nItem == -1 || nSubItem == -1)
{
return -1;
}
CString cstrText = this->GetItemText(nItem, nSubItem);
CRect rcCtrl(0, 0, 0, 0);
this->GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rcCtrl);
rcCtrl.bottom += 200;
pCombo->MoveWindow(&rcCtrl);
pCombo->ShowWindow(SW_SHOW);
pCombo->SetCurSel(-1);
pCombo->SetWindowText(cstrText);
pCombo->SetFocus();
int nItems = pCombo->GetCount();
CString cstrComboItemText;
for (int i = 0; i < nItems; ++i)
{
pCombo->GetLBText(i, cstrComboItemText);
if (cstrText == cstrComboItemText)
{
pCombo->SetCurSel(i);
break;
}
}
}
else
{
pCombo->ShowWindow(SW_HIDE);
}
return 0;
}
//-----------------------------------------------------------------------------
// 函数: ShowCombo
// 功能: 显示ComboBox
// 参数:
// pCombo ------ 待显示的ComboBox的指针,该ComboBox必须为调用CListCtrlXE::CreateCombo创建,
// 否则将不会显示,并且函数返回-1
// 返回值:
// 0 ------ 成功
// -1 ------ 失败
//-----------------------------------------------------------------------------
int CListCtrlXE::ShowCombo(CComboBox* pCombo)
{
if (NULL == pCombo)
{
return -1;
}
// 校验pCombo是否由调用CreateCombo创建
bool bFind = false;
list<CComboLCXE*>::iterator iterCombo = m_lstCombo.begin();
for (; iterCombo != m_lstCombo.end(); ++iterCombo)
{
if (*iterCombo == (CComboLCXE*)pCombo)
{
bFind = true;
break;
}
}
if (false == bFind)
{
return -1;
}
// 显示
return this->ShowCombo((CComboLCXE*)pCombo, true);
}
BEGIN_MESSAGE_MAP(CListCtrlXE, CListCtrl)
ON_WM_LBUTTONDBLCLK()
ON_NOTIFY(HDN_BEGINTRACKA, 0, &CListCtrlXE::OnHdnBegintrack)
ON_NOTIFY(HDN_BEGINTRACKW, 0, &CListCtrlXE::OnHdnBegintrack)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_MESSAGE(WM_USER_EDIT_END, OnEditEnd)
ON_MESSAGE(WM_USER_COMBO_END, OnComboEnd)
END_MESSAGE_MAP()
// CListCtrlXE message handlers
LRESULT CListCtrlXE::OnEditEnd(WPARAM wParam, LPARAM lParam)
{
CEditLCXE* pEdit = (CEditLCXE*)wParam;
if (NULL == pEdit)
{
return 0;
}
CString strText;
pEdit->GetWindowText(strText);
this->SetItemText(nItem, nSubItem, strText);
this->ShowEditBox(pEdit, false);
LCXE_EditEndData data;
data.nItem = nItem;
data.nSubItem = nSubItem;
data.pEdit = pEdit;
data.pLCXE = this;
::SendMessage(this->GetParent()->GetSafeHwnd(), MSG_LCXE_EDIT_END, (WPARAM)&data, (LPARAM)&data);
return 0;
}
LRESULT CListCtrlXE::OnComboEnd(WPARAM wParam, LPARAM lParam)
{
CComboLCXE* pCombo = (CComboLCXE*)wParam;
if (NULL == pCombo)
{
return 0;
}
DWORD dwStyle = pCombo->GetStyle();
if ((DWORD)(dwStyle & CBS_DROPDOWNLIST) == (DWORD)CBS_DROPDOWNLIST)
{
int nSel = pCombo->GetCurSel();
CString cstrText;
if (nSel != -1)
{
pCombo->GetLBText(nSel, cstrText);
}
this->SetItemText(nItem, nSubItem, cstrText);
}
else
{
CString cstrText;
pCombo->GetWindowText(cstrText);
this->SetItemText(nItem, nSubItem, cstrText);
}
this->ShowCombo(pCombo, false);
LCXE_ComboEndData data;
data.nItem = nItem;
data.nSubItem = nSubItem;
data.pCombo = pCombo;
data.pLCXE = this;
::SendMessage(this->GetParent()->GetSafeHwnd(), MSG_LCXE_COMBO_END, (WPARAM)&data, (LPARAM)&data);
return 0;
}
void CListCtrlXE::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 CListCtrl::OnLButtonDblClk(nFlags, point);
}
nSubItem = lvhti.iSubItem;
if (nSubItem == -1)
{
return CListCtrl::OnLButtonDblClk(nFlags, point);
}
// 向父窗口发送MSG_LCXE_LBTN_DBLCLICK_CUSTOM消息
LCXE_LBDC_Data data;
data.nItem = nItem;
data.nSubItem = nSubItem;
data.pLCXE = this;
::SendMessage(this->GetParent()->GetSafeHwnd(), MSG_LCXE_LBTN_DBLCLICK_CUSTOM, (WPARAM)&data, (LPARAM)&data);
return CListCtrl::OnLButtonDblClk(nFlags, point);
}
void CListCtrlXE::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
list<CEditLCXE*>::iterator iterEdit = m_lstEdit.begin();
for (; iterEdit != m_lstEdit.end(); ++iterEdit)
{
CEditLCXE* pEdit = *iterEdit;
if (pEdit->GetSafeHwnd() != NULL
&& pEdit->IsWindowVisible())
{
OnEditEnd((WPARAM)pEdit, (LPARAM)pEdit);
}
}
list<CComboLCXE*>::iterator iterCombo = m_lstCombo.begin();
for (; iterCombo != m_lstCombo.end(); ++iterCombo)
{
CComboLCXE* pCombo = *iterCombo;
if (pCombo->GetSafeHwnd() != NULL
&& pCombo->IsWindowVisible())
{
OnComboEnd((WPARAM)pCombo, (LPARAM)pCombo);
}
}
*pResult = 0;
}
void CListCtrlXE::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
list<CEditLCXE*>::iterator iterEdit = m_lstEdit.begin();
for (; iterEdit != m_lstEdit.end(); ++iterEdit)
{
CEditLCXE* pEdit = *iterEdit;
if (pEdit->GetSafeHwnd() != NULL
&& pEdit->IsWindowVisible())
{
OnEditEnd((WPARAM)pEdit, (LPARAM)pEdit);
}
}
list<CComboLCXE*>::iterator iterCombo = m_lstCombo.begin();
for (; iterCombo != m_lstCombo.end(); ++iterCombo)
{
CComboLCXE* pCombo = *iterCombo;
if (pCombo->GetSafeHwnd() != NULL
&& pCombo->IsWindowVisible())
{
OnComboEnd((WPARAM)pCombo, (LPARAM)pCombo);
}
}
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CListCtrlXE::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
list<CEditLCXE*>::iterator iterEdit = m_lstEdit.begin();
for (; iterEdit != m_lstEdit.end(); ++iterEdit)
{
CEditLCXE* pEdit = *iterEdit;
if (pEdit->GetSafeHwnd() != NULL
&& pEdit->IsWindowVisible())
{
OnEditEnd((WPARAM)pEdit, (LPARAM)pEdit);
}
}
list<CComboLCXE*>::iterator iterCombo = m_lstCombo.begin();
for (; iterCombo != m_lstCombo.end(); ++iterCombo)
{
CComboLCXE* pCombo = *iterCombo;
if (pCombo->GetSafeHwnd() != NULL
&& pCombo->IsWindowVisible())
{
OnComboEnd((WPARAM)pCombo, (LPARAM)pCombo);
}
}
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}