相信很多人用过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);
}