MFC实现CListCtrl子项可编辑的简便操作

来源:互联网 发布:dota6.83c数据 编辑:程序博客网 时间:2024/05/17 06:22
相信很多人用过MFC的新手都知道,MFC虽然封装了一些常用的控件,但不少控件真正使用起来,与个人的要求可能会有一些差别,总有一些功能不是很方便就能实现的,例如CTabCtrl(Tab控件)的颜色(涉及到自绘、头大)/CListCtrl的子项编辑。
      这两天用列表控件做东西,需要编辑列表控件的子项,尝试了一通MFC提供的功能,觉得不是很好用,我需要的是报表风格的列表控件,估计不少人都知道,报表风格的列表控件,在资源里设置了“可就地编辑”的属性,子项虽然能够编辑,但编辑框是出现在第一列的,即不管你选择修改的项是在第几列,编辑框总是出现在相应行的第一列位置,很麻烦,而且经过我的尝试,编辑完后的文本保存,也是需要自己实现的。
      总之来说,就是clistctrl控件用的不太爽,于是我就想自己定制一个!在网上搜了一下相关的资料,发现大多数的人都是自己派生一个子类实现,建立一个CEdit对象,然后将该对象的大小设置到与空间的格子一样大小,当双击或者单击(看个人实现)时候,将该CEdit编辑框show出来,实现编辑功能,响应CEdit编辑框失去焦点消息,将编辑框的文本SetItemText到列表控件中。
      这种实现我觉得很不错,不过就是要派生自己的类,同时还要处理一些定位的消息,这里面就设计到一个讨厌的函数int (CPoint pt,UINT* pFlags=NULL) const,该函数还有一个重载版本的(参数忘了,具体查查MSDN或者百度吧),这个函数返回列表控件相应的行数,不知道为什么,我自己在实现的时候总是返回-1,就算用了ScreenToClient转换了都用,比较头大,看来是不行了,百度啊百度,然后我就看到另外一个办法!以下具体讲讲我的实现吧!
      为了简便实现,我没有派生子类,直接在对话框上拖入一个CListCtrl列表控件,设置后属性,风格(报表-report),在对话框初始化函数里加入列表控件的一些初始化操作,这些就跳过了!下来是实现子项编辑的关键部分。
      资源里拖入一个CEdit Box控件,关联control变量m_SubItemEdit,关联value变量CString cstrItemTextEdit,在对话框初始化函数OnInitDialog()里将编辑框隐藏起来:m_SubItemEdit.ShowWindow(SW_HIDE);
      响应CListCtrl控件的NM_DBLCLK(指示用户在控件内双击了鼠标左键),以下是响应函数的处理,实现子项的可编辑化。
[cpp] view plaincopyprint?
  1. void CPetDialog::OnNMDblclkList2(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     //LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);  
  4.     // TODO: 在此添加控件通知处理程序代码   
  5.     NM_LISTVIEW *pNMListCtrl = (NM_LISTVIEW *)pNMHDR;  
  6.     if(pNMListCtrl->iItem != -1)  
  7.     {  
  8.         CRect rect,dlgRect;  
  9.         //获得当前列的宽度以适应如果用户调整宽度   
  10.         //此处不用获得的子项rect矩形框来设置宽度   
  11.         //是因第一列时返回的宽度是整行的宽度,我也不知道为啥  
  12.         int width = m_ListCtrlBuy.GetColumnWidth(pNMListCtrl->iSubItem);  
  13.         m_ListCtrlBuy.GetSubItemRect(pNMListCtrl->iItem,pNMListCtrl->iSubItem,LVIR_BOUNDS,rect);  
  14.         //保存选择的列表项索引   
  15.         //这个因为我是用了两个列表控件一个CEdit  
  16.         //所以需要保存列表的索引   
  17.         //以及子项相对应的行列号索引   
  18.         listSelFlag[0] = 1;//列表1   
  19.         listSelFlag[1] = pNMListCtrl->iItem;  
  20.         listSelFlag[2] = pNMListCtrl->iSubItem;  
  21.         //获得listctrl矩形框   
  22.         //获得父对话框的位置以调整CEdit的显示位置,具体见下面代码   
  23.         m_ListCtrlBuy.GetWindowRect(&dlgRect);  
  24.         //调整与父窗口对应   
  25.         ScreenToClient(&dlgRect);  
  26.         int height = rect.Height();  
  27.         rect.top += (dlgRect.top+1);  
  28.         rect.left += (dlgRect.left+1);  
  29.         rect.bottom = rect.top+height+2;  
  30.         rect.right = rect.left+width+2;  
  31.         m_SubItemEdit.MoveWindow(&rect);  
  32.         m_SubItemEdit.ShowWindow(SW_SHOW);  
  33.         m_SubItemEdit.SetFocus();  
  34.     }  
  35.     //*pResult = 0;   
  36. }  
 
      到了这里,应该就可以实现双击编辑控件了,但只是编辑而已,没有实现保存,要实现保存,还得对CEDIT失去焦点消息进行相应,以下是响应函数,因为我还做了CEdit控件对于回车键实现保存编辑的功能,所以做了一个保存函数,下面是实现!
//保存编辑框的文本函数
[c-sharp] view plaincopyprint?
  1. void CPetDialog::SetListItemText(void)  
  2. {  
  3.     UpdateData(TRUE);  
  4.     //AfxMessageBox(cstrItemTextEdit);   
  5.     if(listSelFlag[0] == 2)//出售列表  
  6.     {  
  7.         //此处的cstrItemTextEdit是CEdit控件的字符串关联变量  
  8.         m_ListCtrlNotSell.SetItemText(listSelFlag[1],listSelFlag[2],cstrItemTextEdit);  
  9.         //重置编辑框文本   
  10.         m_SubItemEdit.SetWindowText(L"");  
  11.         //隐藏编辑框   
  12.         m_SubItemEdit.ShowWindow(SW_HIDE);  
  13.     }  
  14.     if(listSelFlag[0] == 1)//购买列表  
  15.     {  
  16.         m_ListCtrlBuy.SetItemText(listSelFlag[1],listSelFlag[2],cstrItemTextEdit);  
  17.         m_SubItemEdit.SetWindowText(L"");  
  18.         m_SubItemEdit.ShowWindow(SW_HIDE);  
  19.     }  
  20.     //强制刷新列表控件(否则视觉上有感觉有点不爽,可以试试^_^)   
  21.     m_ListCtrlNotSell.Invalidate();  
  22. }  
 
//响应CEdit控件的EN_KILLFOCUS函数
[cpp] view plaincopyprint?
  1. void CPetDialog::OnEnKillfocusEdit2()  
  2. {  
  3.     // TODO: 在此添加控件通知处理程序代码   
  4.     SetListItemText();  
  5. }  
 
//因为要处理回车键的响应,所以直接重载CLISTCTRL控件所在的对话框PreTranslateMessage函数,然后在函数里做处理
[cpp] view plaincopyprint?
  1. BOOL CPetDialog::PreTranslateMessage(MSG* pMsg)  
  2. {  
  3.     // TODO: 在此添加专用代码和/或调用基类   
  4.     if ( pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN )   
  5.     {     
  6.         if( GetFocus()->GetDlgCtrlID() == IDC_EDIT2)  
  7.         {  
  8.             if(listSelFlag[0] == 1)  
  9.                 m_ListCtrlBuy.SetFocus();//使列表控件获得焦点,则CEdit会自动失去焦点,触发EN_KILLFOCUS消息  
  10.             if(listSelFlag[0] == 2)  
  11.                 m_ListCtrlNotSell.SetFocus();  
  12.         }  
  13.         return TRUE;  
  14.     }  
  15.     return CDialog::PreTranslateMessage(pMsg);  
  16. }  
 
      到这里,就是CListCtrl控件的子项编辑化实现的全部内容了,用的是我自己的代码,磕磕碰碰的,体会到了新手的难处,觉得还是写出来分享一下的好,如果有更好更简便的实现方法,高手们请多多指点!
      顺便看看我的效果吧,嘻嘻!