VS MFC中List Control控件的使用
List Control控件是MFC中常用的列表展示控件,支持报告视图、图标视图等多种显示方式。以下是详细功能实现及代码示例。
控件初始化与数据插入
在对话框类头文件中声明控件变量:
CListCtrl m_listCtrl;
在OnInitDialog()中初始化控件:
m_listCtrl.InsertColumn(0, _T("ID"), LVCFMT_LEFT, 80);
m_listCtrl.InsertColumn(1, _T("Name"), LVCFMT_LEFT, 120);
m_listCtrl.InsertColumn(2, _T("Value"), LVCFMT_LEFT, 100);
m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
插入数据示例:
int nItem = m_listCtrl.InsertItem(0, _T("1001"));
m_listCtrl.SetItemText(nItem, 1, _T("Item1"));
m_listCtrl.SetItemText(nItem, 2, _T("50.0"));
实现双击修改功能
添加NM_DBLCLK消息处理:
void CYourDlg::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
if (pNMIA->iItem != -1 && pNMIA->iSubItem != -1)
{
CRect rect;
m_listCtrl.GetSubItemRect(pNMIA->iItem, pNMIA->iSubItem, LVIR_LABEL, rect);
CString strText = m_listCtrl.GetItemText(pNMIA->iItem, pNMIA->iSubItem);
CEdit* pEdit = new CEdit;
pEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER, rect, &m_listCtrl, IDC_EDIT);
pEdit->SetWindowText(strText);
pEdit->SetFocus();
}
*pResult = 0;
}
编辑框处理逻辑
添加编辑框的EN_KILLFOCUS消息处理:
void CYourDlg::OnEnKillfocusEdit()
{
CEdit* pEdit = (CEdit*)GetDlgItem(IDC_EDIT);
if (pEdit)
{
CString strText;
pEdit->GetWindowText(strText);
LVHITTESTINFO info;
GetCursorPos(&info.pt);
m_listCtrl.ScreenToClient(&info.pt);
m_listCtrl.SubItemHitTest(&info);
if (info.iItem != -1 && info.iSubItem != -1)
{
m_listCtrl.SetItemText(info.iItem, info.iSubItem, strText);
}
pEdit->DestroyWindow();
delete pEdit;
}
}
完整功能实现要点
- 控件样式设置应包含
LVS_EX_FULLROWSELECT和LVS_EX_GRIDLINES以获得更好视觉效果 - 双击事件需判断有效的行列索引
- 动态创建编辑框时需正确定位到对应单元格
- 编辑框失去焦点时应保存数据并销毁控件
- 可添加输入验证逻辑确保数据有效性
高级功能扩展
支持不同类型编辑控件
可根据列数据类型创建不同编辑控件:
if (pNMIA->iSubItem == 2) // 数值列
{
CSpinButtonCtrl* pSpin = new CSpinButtonCtrl;
pSpin->Create(WS_CHILD|WS_VISIBLE, rect, &m_listCtrl, IDC_SPIN);
// 设置数值范围等属性
}
数据验证示例
在保存前验证输入:
double dValue = _ttof(strText);
if (dValue < 0 || dValue > 100)
{
MessageBox(_T("请输入0-100之间的数值"));
return;
}
性能优化建议
对于大数据量列表:
- 使用
SetRedraw(FALSE)和SetRedraw(TRUE)减少重绘 - 批量操作时使用
BeginUpdate和EndUpdate - 考虑虚拟列表技术(LVS_OWNERDATA)
实现列表内容编辑功能
扩展List Control的编辑功能
通过子类化CListCtrl并处理特定消息(如NM_DBLCLK、LVN_ENDLABELEDIT)实现双击编辑。示例代码框架:
class CEditableListCtrl : public CListCtrl {
protected:
afx_msg void OnDblClk(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CEditableListCtrl, CListCtrl)
ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblClk)
ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit)
END_MESSAGE_MAP()
实现单元格双击编辑
在双击事件中触发编辑控件:
void CEditableListCtrl::OnDblClk(NMHDR* pNMHDR, LRESULT* pResult) {
LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
if (pNMIA->iItem >= 0 && pNMIA->iSubItem >= 0) {
CEdit* pEdit = new CEdit;
CRect rect;
GetSubItemRect(pNMIA->iItem, pNMIA->iSubItem, LVIR_LABEL, rect);
pEdit->Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, rect, this, IDC_EDIT);
}
*pResult = 0;
}
添加下拉列表支持
对于特定列,使用CComboBox替代CEdit:
void CEditableListCtrl::OnDblClk(NMHDR* pNMHDR, LRESULT* pResult) {
LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
if (pNMIA->iSubItem == DROPDOWN_COL_INDEX) {
CComboBox* pCombo = new CComboBox;
CRect rect;
GetSubItemRect(pNMIA->iItem, pNMIA->iSubItem, LVIR_LABEL, rect);
pCombo->Create(WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST, rect, this, IDC_COMBO);
pCombo->AddString(_T("Option1"));
pCombo->AddString(_T("Option2"));
pCombo->SetCurSel(0);
}
}
处理编辑完成事件
保存修改后的数据到List Control:
void CEditableListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
if (pDispInfo->item.pszText) {
SetItemText(pDispInfo->item.iItem, pDispInfo->item.iSubItem, pDispInfo->item.pszText);
}
*pResult = 0;
}
内存管理优化
防止控件内存泄漏:
void CEditableListCtrl::OnDestroy() {
CEdit* pEdit = (CEdit*)GetDlgItem(IDC_EDIT);
if (pEdit) pEdit->DestroyWindow();
CComboBox* pCombo = (CComboBox*)GetDlgItem(IDC_COMBO);
if (pCombo) pCombo->DestroyWindow();
CListCtrl::OnDestroy();
}
动态列类型判断
根据列索引决定控件类型:
bool IsDropdownColumn(int nCol) {
return (nCol == 1 || nCol == 3); // 示例:第2和第4列使用下拉框
}
4694

被折叠的 条评论
为什么被折叠?



