天天看点

CListCtrl 编辑子项

相信很多人用过MFC的新手都知道,MFC虽然封装了一些常用的控件,但不少控件真正使用起来,与个人的要求可能会有一些差别,总有一些功能不是很方便就能实现的,例如CTabCtrl(Tab控件)的颜色(涉及到自绘、头大)/CListCtrl的子项编辑。 报表风格的列表控件,在资源里设置了“可就地编辑”的属性,子项虽然能够编辑,但编辑框是出现在第一列的,即不管你选择修改的项是在第几列,编辑框总是出现在相应行的第一列位置,很麻烦,而且经过我的尝试,编辑完后的文本保存,也是需要自己实现的。

为了简便实现,我没有派生子类,而是在资源中添加一个编辑框,通过将编辑框显示隐藏在指定位置,达到可编辑的目的,在编辑框失去焦点时,将文本显示在ListCtrl中。

下面是我的实现方法:

  1.  资源里拖入一个CEdit Box控件,关联control变量m_SubItemEdit,关联value变量CString m_strEditText,在对话框初始化函数OnInitDialog()里将编辑框隐藏起来:           m_SubItemEdit.ShowWindow(SW_HIDE);

2.   在对话框上拖入一个CListCtrl列表控件,设置后属性,风格(报表-report),添加变量m_ListCtrl,在对话框初始化函数里加入列表控件的一些初始化操作,

     在 OninitDialog中初始化列表框:

    m_ListCtrl.SetExtendedStyle( //设置风格

                LVS_EX_FLATSB            //扁平风格滚动条

                | LVS_EX_FULLROWSELECT    //允许整行选中

                | LVS_EX_HEADERDRAGDROP   //允许标题拖拽

                | LVS_EX_ONECLICKACTIVATE //高亮显示

                | LVS_EX_GRIDLINES        //画出网格线

                );

        m_ListCtrl.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 150, 0);

        m_ListCtrl.InsertColumn(1, _T("联系电话"), LVCFMT_LEFT, 150, 1);

        m_ListCtrl.InsertItem(0, _T(""));

        m_ListCtrl.SetItemText(0, 0, _T("周芷若"));

        m_ListCtrl.SetItemText(0, 1, _T("123456789"));

        m_ListCtrl.InsertItem(1, _T(""));

        m_ListCtrl.SetItemText(1, 0, _T("张无忌"));

        m_ListCtrl.SetItemText(1, 1, _T("987654321"));

        m_SubItemEdit.ShowWindow(SW_HIDE);

    3.  响应CListCtrl控件的NM_DBLCLK(指示用户在控件内双击了鼠标左键),以下是响应函数的处理,实现子项的可编辑化。

void CEditListCtrlDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)

{

        //LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);

        // TODO:  在此添加控件通知处理程序代码

        //*pResult = 0;

        NM_LISTVIEW *pNMListCtrl = (NM_LISTVIEW *)pNMHDR;

        if (pNMListCtrl->iItem != -1)

        {

                CRect rect, dlgRect;

                //获得当前列的宽度以适应如果用户调整宽度   

                //此处不用获得的子项rect矩形框来设置宽度   

                //是因第一列时返回的宽度是整行的宽度,我也不知道为啥   

                int width = m_ListCtrl.GetColumnWidth(pNMListCtrl->iSubItem);

                m_ListCtrl.GetSubItemRect(pNMListCtrl->iItem, pNMListCtrl->iSubItem, LVIR_BOUNDS, rect);

                //所以需要保存列表的索引   

                //以及子项相对应的行列号索引  

                listSelItem[0] = pNMListCtrl->iItem;

                listSelItem[1] = pNMListCtrl->iSubItem;

                //获得listctrl矩形框   

                //获得父对话框的位置以调整CEdit的显示位置,具体见下面代码   

                m_ListCtrl.GetWindowRect(&dlgRect);

                ScreenToClient(&dlgRect);

                int height = rect.Height();

                rect.top += (dlgRect.top + 1);

                rect.left += (dlgRect.left + 1);

                rect.bottom = rect.top + height + 2;

                rect.right = rect.left + width + 2;

                m_SubItemEdit.MoveWindow(&rect);

                m_SubItemEdit.ShowWindow(SW_SHOW);

                m_SubItemEdit.SetFocus();

        }

}

4.到了这里,应该就可以实现双击编辑控件了,但只是编辑而已,没有实现保存,要实现保存,还得对CEDIT失去焦点消息进行相应,以下是响应函数,因为我还做了CEdit控件对于回车键实现保存编辑的功能

void CEditListCtrlDlg::SetListItemText(void)

{

        UpdateData(TRUE);

                //此处的cstrItemTextEdit是CEdit控件的字符串关联变量   

                m_ListCtrl.SetItemText(listSelItem[0], listSelItem[1], m_strEditText);

                //重置编辑框文本   

                m_SubItemEdit.SetWindowText(_T(""));

                //隐藏编辑框   

                m_SubItemEdit.ShowWindow(SW_HIDE);

        //强制刷新列表控件(否则视觉上有感觉有点不爽,可以试试^_^)   

           m_ListCtrl.Invalidate();

}

5.   响应CEdit控件的EN_KILLFOCUS函数

void CEditListCtrlDlg::OnEnKillfocusEdit1()

{

        // TODO:  在此添加控件通知处理程序代码

        SetListItemText();

}

6.处理回车键的响应,所以直接重载对话框的PreTranslateMessage函数,然后在函数里做处理

BOOL CEditListCtrlDlg::PreTranslateMessage(MSG* pMsg)

{

        // TODO:  在此添加专用代码和/或调用基类

        if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)

        {

                if (GetFocus()->GetDlgCtrlID() == IDC_EDIT1)

                {

                        //使列表控件获得焦点,则CEdit会自动失去焦点,触发EN_KILLFOCUS消息   

                                m_ListCtrl.SetFocus();

                }

                return TRUE;

        }

        return CDialogEx::PreTranslateMessage(pMsg);

}

vc