MFC列表控件实战:双击修改与数据验证

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;
    }
}

完整功能实现要点
  1. 控件样式设置应包含LVS_EX_FULLROWSELECTLVS_EX_GRIDLINES以获得更好视觉效果
  2. 双击事件需判断有效的行列索引
  3. 动态创建编辑框时需正确定位到对应单元格
  4. 编辑框失去焦点时应保存数据并销毁控件
  5. 可添加输入验证逻辑确保数据有效性

高级功能扩展

支持不同类型编辑控件

可根据列数据类型创建不同编辑控件:

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)减少重绘
  • 批量操作时使用BeginUpdateEndUpdate
  • 考虑虚拟列表技术(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列使用下拉框
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值