• 可编辑子项的CListCtrl类


    关于实用又方面“可编辑CListCtrl类”我之前也找了许久,终于被我找到了,与前面一篇那个效果一模一样...

    1、使用说明

    本文对CListCtrl控件进行了一个扩展,使它即可以编辑主项(Item),又可以编辑子项(SubItem),并尽量符合CListCtrl的操作习惯。

    大家都知道在MFC中通过给CListCtrl设置LVS_EDITLABELS属性,并且在程序中响应控件的LVN_ENDLABELEDIT消息可以修改列表控件每一行的第一项,也就是主项(Item)。代码如下 :

    1. void CEditListCtrlSampleDlg::OnEndlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult)  
    2.     LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
    3.     // TODO: Add your control notification handler code here 
    4.      
    5.     *pResult = TRUE;   //TRUE值表示可以修改主项,FALSE值表示不修改主项 

    但是让人郁闷的是,微软留了一手,CListCtrl不支持直接修改子项(SubItem)。无奈之下只好自力更生,对CListCtrl进行扩展。

    2、主要原理

    通过在浩如烟海的互联网上查找资料(当然包括了大名鼎鼎的VCKBASE),发现现有的实现大都是对子项鼠标单击一次就可以编辑。但本人对CListCtrl的单击一次高亮文本,再单击一次才开始编辑的操作模式感觉比较喜欢,所以就有了这篇文章的诞生。
    要想实现高亮文本也就是对文本进行着色处理,这可以通过对NM_CUSTOMDRAW消息进行处理实现,但是类向导中没有这个消息映射只能进行手工添加。

    要想编辑文本则可以通过EditLabel(int nItem)成员函数以及对LVN_BEGINLABELEDIT和LVN_ENDLABELEDIT的消息处理实现。

    3、实现代码

    本文最终实现的CEditListCtrl扩展类在尽量符合CListCtrl操作步骤的情况下实现对主项及子项的可编辑。成员变量说明:

    1. int       m_iItem;       //主项标识符 
    2. int       m_iSubItem;    //子项标识符 
    3. BOOL      m_bFocus;      //是否绘制项文本焦点框 
    4. BOOL      m_bHighLight;  //是否高亮项文本 
    5. CItemEdit m_edtItemEdit; //用于子类化EditLabel函数返回的CEdit*指针 

    列表控件中所有项文本的绘制以及特效(焦点框、高亮)都在NM_CUSTOMDRAW消息处理中实现:

    1. void CEditListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 
    2.     NMLVCUSTOMDRAW* pNMLVCustomDraw = (NMLVCUSTOMDRAW*)pNMHDR; 
    3.      
    4.     // Take the default processing unless we set this to something else below. 
    5.     *pResult = CDRF_DODEFAULT; 
    6.      
    7.     // First thing - check the draw stage. If it's the control's prepaint 
    8.     // stage, then tell Windows we want messages for every item. 
    9.      
    10.     if (pNMLVCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) 
    11.     { 
    12.         *pResult = CDRF_NOTIFYITEMDRAW; 
    13.     } 
    14.     else if (pNMLVCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) 
    15.     { 
    16.         // This is the notification message for an item.  We'll request 
    17.         // notifications before each subitem's prepaint stage. 
    18.         *pResult = CDRF_NOTIFYSUBITEMDRAW; 
    19.     } 
    20.     else if (pNMLVCustomDraw->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)) 
    21.     { 
    22.         //当前要绘制的主项标识符和子项标识符 
    23.         int iItem = (int)pNMLVCustomDraw->nmcd.dwItemSpec; 
    24.         int iSubItem = pNMLVCustomDraw->iSubItem; 
    25.          
    26.         CDC* pDC = CDC::FromHandle(pNMLVCustomDraw->nmcd.hdc); 
    27.          
    28.         CString strItemText = GetItemText(iItem, iSubItem); 
    29.         CRect rcItem, rcText; 
    30.         GetSubItemRect(iItem, iSubItem, LVIR_LABEL, rcItem); 
    31.         rcText = rcItem; 
    32.          
    33.         CSize size = pDC->GetTextExtent(strItemText); 
    34.         if(strItemText == _T("")) 
    35.         { 
    36.             size.cx = 41;  
    37.         } 
    38.          
    39.         //设置文本高亮矩形 
    40.         rcText.left += 4; 
    41.         rcText.right = rcText.left + size.cx + 6; 
    42.             if(rcText.right > rcItem.right) 
    43.     { 
    44.         rcText.right = rcItem.right; 
    45.     } 
    46.          
    47.     COLORREF crOldTextColor = pDC->GetTextColor(); 
    48.  
    49.     //绘制项焦点/高亮效果 
    50.     if(m_bFocus) 
    51.     { 
    52.         if((m_iItem == iItem) && (m_iSubItem == iSubItem)) 
    53.         {    
    54.             if(m_bHighLight) 
    55.             {                    
    56.                 pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT)); 
    57.                 pDC->FillSolidRect(&rcText, ::GetSysColor(COLOR_HIGHLIGHT)); 
    58.             } 
    59.             pDC->DrawFocusRect(&rcText); 
    60.         }        
    61.     } 
    62.          
    63.     //绘制项文本 
    64.     rcItem.left += 6; 
    65.     pDC->DrawText(strItemText, &rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP); 
    66.  
    67.     pDC->SetTextColor(crOldTextColor); 
    68.     *pResult = CDRF_SKIPDEFAULT;// We've painted everything. 
    69.     }    

    单击一次文本高亮,再单击一次文本开始编辑在WM_LBUTTONDOWN消息处理中实现:

    1. void CEditListCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
    2.     m_bFocus = TRUE; 
    3.     LVHITTESTINFO  lvhit; 
    4.     lvhit.pt = point; 
    5.     int item = SubItemHitTest(&lvhit); 
    6.      
    7.     //if (over a item/subitem) 
    8.     if (item != -1 && (lvhit.flags & LVHT_ONITEM)) 
    9.     { 
    10.         CListCtrl::OnLButtonDown(nFlags, point); 
    11.          
    12.         if(m_bHighLight && m_iItem == lvhit.iItem && m_iSubItem == lvhit.iSubItem) 
    13.         { 
    14.             //第二次单击 
    15.             EditLabel(m_iItem); 
    16.             return
    17.         } 
    18.         else 
    19.         { 
    20.             //第一次单击 
    21.             m_iItem = lvhit.iItem; 
    22.             m_iSubItem = lvhit.iSubItem; 
    23.             m_bHighLight = TRUE; 
    24.         } 
    25.     } 
    26.     else 
    27.     { 
    28.         if(m_edtItemEdit.m_hWnd == NULL) 
    29.         { 
    30.             //未出现文本编辑框时 
    31.             m_bHighLight = FALSE; 
    32.         } 
    33.          
    34.         CListCtrl::OnLButtonDown(nFlags, point); 
    35.     } 
    36.      
    37.     Invalidate(); //强制重绘控件 

    关键的一步,对项文本进行编辑。在以上代码中当执行到EditLabel时将会产生一个编辑框,这时需要将它进行子类化处理,以控制它出现的位置:

    1. void CEditListCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)  
    2.     LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
    3.  
    4.     if (m_iSubItem >= 0) 
    5.     { 
    6.         ASSERT(m_iItem == pDispInfo->item.iItem); 
    7.         CRect  rcSubItem; 
    8.         GetSubItemRect( pDispInfo->item.iItem, m_iSubItem, LVIR_BOUNDS, rcSubItem); 
    9.          
    10.         //get edit control and subclass 
    11.         HWND hWnd= (HWND)SendMessage(LVM_GETEDITCONTROL); 
    12.         ASSERT(hWnd != NULL); 
    13.         VERIFY(m_edtItemEdit.SubclassWindow(hWnd)); 
    14.  
    15.         //move edit control text 4 pixel to the right of org label, 
    16.         //as Windows does it...编辑框定位 
    17.         m_edtItemEdit.m_iXPos = rcSubItem.left + 4; 
    18.         m_edtItemEdit.SetWindowText(GetItemText(pDispInfo->item.iItem, m_iSubItem)); 
    19.     } 
    20.  
    21.     *pResult = 0; 
    22.  
    23. void CEditListCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)  
    24.     LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
    25.     LV_ITEM *plvItem = &pDispInfo->item; 
    26.      
    27.     if (m_iSubItem >= 0) 
    28.     { 
    29.         if (plvItem->pszText != NULL ) 
    30.         { 
    31.             SetItemText(plvItem->iItem,m_iSubItem, plvItem->pszText); 
    32.         } 
    33.          
    34.         VERIFY(m_edtItemEdit.UnsubclassWindow()!=NULL);  
    35.         *pResult = 0; 
    36.     } 
    37.  
    38.     //编辑文本时对控件父窗口操作(如单击其它控件)引发"OnEndlabeledit"时刷新控件 
    39.     CRect rect; 
    40.     GetWindowRect(&rect); 
    41.     CPoint point; 
    42.     ::GetCursorPos(&point); 
    43.     if(!rect.PtInRect(point)) 
    44.     { 
    45.         m_iItem = -1; 
    46.         m_iSubItem = -1; 
    47.         m_bFocus = FALSE; 
    48.         m_bHighLight = FALSE; 
    49.     } 

    4、运行效果

    通过以上三个步骤大体实现了本文要达到的目的,但是还不能放松。接下来还要进行一些显示细节方面的处理。这包括对WM_PAINT、WM_SETFOCUS和WM_KILLFOCUS消息的处理,限于篇幅,就不进行细讲了,有兴趣的朋友可以查看本文提供的源代码。 最后实现的效果如下图所示:

    可编辑的ListCtrl

    5、源码下载:

         下载地址1:实例代码

         下载地址2:官方下载

    本文转自中文版Code Project:http://www.hellocpp.net/Articles/Article/254.aspx

  • 相关阅读:
    作妖系列——更改spyder黑色主题
    latex beamer 插入代码
    LaTeX 如何在文档的侧面插入图片实现"绕排"?
    svm
    约束优化方法之拉格朗日乘子法与KKT条件
    Latex algorithm
    对于连续目标函数的学习问题,当误差为正态分布,而且在没有任何先验知识的条件下,最大似然估计与最小均方误差等价
    R语言table()函数
    高性能Linux服务器配置
    深度学习
  • 原文地址:https://www.cnblogs.com/lidabo/p/2848754.html
Copyright © 2020-2023  润新知