Simplified Subitem Editing



Click here for a larger image.

Environment: VC6 SP5

This article suggests a way to subclass the listviews edit control, but unlike the article "Editing listview Subitems Using LVM_GETEDITCONTROL," it uses a much simpler and hopefully better method. Give it a try!

  1. Vars
    public:
      CSubEdit m_editWnd;
      int m_item;
      int m_subitem;
    
    CSubeditListView::CSubeditListView()
    {
      m_subitem = 0;
    }
    
  2. Detect subitem mouse clicks
    void CSubeditListView::OnLButtonDown(UINT nFlags, CPoint point)
    {
      LVHITTESTINFO  lvhit;
      lvhit.pt = point;
      int item = GetListCtrl().SubItemHitTest(&lvhit);
    
      //if (over a subitem)
      if (item != -1 && lvhit.iSubItem && (lvhit.flags & 
                        LVHT_ONITEM ))
        {
        //mouse click outside the editbox in an already
        //editing cell cancels editing
        if (m_subitem == lvhit.iSubItem && item == m_item)
          {
          CListView::OnLButtonDown(nFlags, point);
          }
        else
          {
          CListView::OnLButtonDown(nFlags, point);
    
          m_subitem = lvhit.iSubItem;
          m_item = item;
          GetListCtrl().EditLabel(item);
          }
    
        }
      else
        CListView::OnLButtonDown(nFlags, point);
    }
    
  3. Handle OnBeginLabelEdit
    void CSubeditListView::OnBeginLabelEdit(NMHDR* pNMHDR,
        LRESULT* pResult)
    {
      LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
    
      //if (subitem selected for editing)
      if (m_subitem)
        {
        ASSERT(m_item == pDispInfo->item.iItem);
    
        CRect  subrect;
        GetListCtrl().GetSubItemRect( pDispInfo->item.iItem,
                                      m_subitem,
            LVIR_BOUNDS , subrect );
    
        //get edit control and subclass
        HWND hWnd=(HWND)SendMessage(LVM_GETEDITCONTROL);
        ASSERT(hWnd!=NULL);
        VERIFY(m_editWnd.SubclassWindow(hWnd));
    
        //move edit control text 1 pixel to the right of org label,
        //as Windows does it...
        m_editWnd.m_x=subrect.left + 6; 
        m_editWnd.SetWindowText(GetListCtrl().GetItemText
            (pDispInfo->item.iItem,m_subitem));
    
        //hide subitem text so it don't show if we delete some
        //text in the edit control
        //OnPaint handles other issues also regarding this
        CRect  rect;
        GetListCtrl().GetSubItemRect(pDispInfo->item.iItem,m_subitem,
            LVIR_LABEL ,rect);
        CDC* hDc = GetDC();
        hDc->FillRect(rect,&CBrush(::GetSysColor(COLOR_WINDOW)));
        ReleaseDC(hDc);
    
        }
    
      //return: editing permitted
      *pResult = 0;
    
    }
    
  4. Positioning the editcontrol
    void CSubEdit::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
    {
      lpwndpos->x=m_x;
    
      CEdit::OnWindowPosChanging(lpwndpos);
    }
    
  5. Handle painting
    void CSubeditListView::OnPaint()
    {
      //if (subitem editing)
      if (m_subitem)
        {
    
        CRect  rect;
        CRect  editrect;
    
        GetListCtrl().GetSubItemRect(m_item,m_subitem,LVIR_LABEL,
                                     rect);
    
        m_editWnd.GetWindowRect(editrect);
        ScreenToClient(editrect);
    
        //block text redraw of the subitems text (underneath the
        //editcontrol)
        //if we didn't do this and deleted some text in the edit
        //control, the subitems original label would show
        if (editrect.right < rect.right)
          {
          rect.left = editrect.right ;
          ValidateRect(rect);
          }
    
        //block filling redraw of leftmost item (caused by FillRect)
        GetListCtrl().GetItemRect(m_item,rect,LVIR_LABEL );
        ValidateRect(rect);
        }
    
      CListView::OnPaint();
    }
    
  6. Handle resizing
    void CSubeditListView::OnSize(UINT nType, int cx, int cy)
    {
      //stop editing if resizing
      if( GetFocus() != this ) SetFocus();
    
      CListView::OnSize(nType, cx, cy);
    
    }
    
  7. Handle OnEndLabelEdit
    void CSubeditListView::OnEndLabelEdit(NMHDR* pNMHDR,
                                          LRESULT* pResult)
    {
      LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
      LV_ITEM  *plvItem = &plvDispInfo->item;
    
      //if (end of sub-editing) do cleanup
      if (m_subitem)
        {
        //plvItem->pszText is NULL if editing canceled
        if (plvItem->pszText != NULL )
          GetListCtrl().SetItemText(plvItem->iItem,m_subitem,
              plvItem->pszText);
    
        VERIFY(m_editWnd.UnsubclassWindow()!=NULL);
    
        m_subitem = 0;
        //always revert to org label (Windows thinks we are editing
        //the leftmost item)
        *pResult = 0;
        }
      else
        //return: update label on leftmost item
        *pResult = 1;
    
    }
    

Downloads

Download exe - 10 Kb
Download source - 40 Kb


Comments

  • CDialog

    Posted by break; on 08/04/2006 04:13am

    Great stuff, but how to use it in an dialog application with CListCtrl? In my case the message "OnLButtonDown" dont take an efect for my CListCtrl, only for my dialog! thanks break;

    Reply
  • Better edit box creation timing

    Posted by swedishbricks on 02/16/2006 05:19pm

    If you replace the handler for WM_LBUTTONDOWN with a handler for NM_CLICK that looks like this:
    
    LRESULT CEditListView::OnClick(LPNMHDR nmhdr)
    {
        LPNMITEMACTIVATE    nmia = \ reinterpret_cast(nmhdr);
    
        LVHITTESTINFO       lvhit;
        lvhit.pt = nmia->ptAction;
        int                 HitItem = SubItemHitTest(&lvhit);
    
        // If the click was on a subitem text of a selected   
        // item and we are not already editing something
        if (HitItem != -1 && lvhit.iSubItem > 0 && 
            (lvhit.flags & LVHT_ONITEMLABEL) != 0 &&
            GetSelectedCount() > 0 && 
            GetItemState(HitItem, LVIS_SELECTED) != 0 &&
            GetEditControl() == NULL)
        {
            // Remember the subitem that we are working on here
            m_Item = HitItem;
            m_Subitem = lvhit.iSubItem;
        }
    
        // Let the default handling do it's thing
        SetMsgHandled(FALSE);
    
        // NM_CLICK doesn't care about the return value
        return 0;
    }
    
    
    ... you will get the edit box displayed with the same delayed timing for subitems as for the main item.
    
    Cheers,
    
    -- Matt

    Reply
  • Problem using CListCtrl

    Posted by Legacy on 12/16/2003 12:00am

    Originally posted by: Shashi Prabhakar

    Your solution is very simple and elegant.  I was wondering what changes you would suggest making to your code to make it work with CListCtrl (instead of CListView).
    
    

    My efforts at doing this thus far have run into the following problems:

    a) If I edit the second (of two) columns, the text in the first column disappears. It returns when the edit operation is ended.

    b) Inclusion of the OnPaint method results in the contents of the List control not being displayed (I do not know why). Also, the application seemed to slow down considerably. I must note here that I apparently cannot call CListCtrl::OnPaint directly from the OnPaint handler in my derived class, since MFC expressly forbids this in the comments of the handler. The only way I could see the list control's contents was if I do NOT override the WM_PAINT handler. I have tried other ways of updating the window (Invalidate, UpdateWindow, etc) to no avail.

    c) Removal of the OnPaint method resulted in the problem of seeing original text below the edit control if you erased the text in the edit control (reason is obvious from the code).

    Any help you can offer would be much appreciated,

    Thanks,

    Shashi

    • Problem using CListCtrl

      Posted by imbtf on 06/27/2004 09:50am

      Make sure "CPaintDC dc(this);" is NOT present in your OnPaint(); Also, at the end of OnPaint(), immedtiately before it returns call "DefWindowProc(WM_PAINT, NULL, NULL);" This will remove the problem of the first item not being displayed when editing subitems.

      Reply
    • CListCtrl

      Posted by hankdane on 06/01/2004 07:32pm

      I used the control with a CListCtrl, and it works just fine. I just removed all calls to GetListCtrl(). I also see the text disappearence problem. If I find a solution, I will post it here.

      Reply
    Reply
  • beginner's question

    Posted by Legacy on 11/10/2003 12:00am

    Originally posted by: gatsby

    i need help, guys:
    i need to use the editable item and subitem on a dialog based application. what should i do?
    thanks.

    • Use the Control

      Posted by hankdane on 06/01/2004 07:35pm

      You can use Gunnar's control from a dialog based application. I did.

      Reply
    Reply
  • Bug plus solution

    Posted by Legacy on 07/17/2003 12:00am

    Originally posted by: Sander

    Hi,


    Great stuff. Been having one problem, though.

    When the view is resized or populated so that a vertical scroll bar is necessary, a problem occurs when exiting the application.

    This only happens in debug mode and the call stack at the particular point is very unclear, as "our list view class" is nowhere in it.
    Though, it seems to have to do with the OnSize implementation of this solution.

    I think that this:

    if( GetFocus() != this ) SetFocus();

    ...should be something like this:

    if( "in edit mode" )
    if( GetFocus() != this ) SetFocus();

    However, if you look at how Windows does this normally for you (thus when editing the main item, not a sub item) just leaving this out immitates best the normal behaviour. Ergo; I removed the OnSize method and am happy again.

    Good luck with it.

    Greetings,


    Sander

    Reply
  • Urgent Help Needed

    Posted by Legacy on 07/09/2003 12:00am

    Originally posted by: Gary

    Hi,
    The list control is wonderful. But, I have one problem. Just as we have CBN_SELCHANGE message in combobox to trap the change of selection event, what event shall I use in this list control? Basically, I want to display related records in a different grid when the selection in list control changes. I could not find the event to do this.
    Please help me.

    Thanks,

    - Gary

    Reply
  • OnLButtonDown?

    Posted by Legacy on 06/02/2003 12:00am

    Originally posted by: real name

    it looks different to system logic (and btw breaks dnd)
    t!

    Reply
  • horizontal scrolling - tip

    Posted by Legacy on 03/12/2003 12:00am

    Originally posted by: marcus gesing

    Here is some example code if you want to make this
    
    solution work even when the user scrolls the list:

    SubEdit1.h:
    old: int m_x;
    new: RECT m_rcSubItem;

    SubEdit1.cpp:
    old: lpwndpos->x = m_x;
    new:
    lpwndpos->x = m_rcSubItem.left;
    lpwndpos->y = m_rcSubItem.top;
    lpwndpos->cx = m_rcSubItem.right;
    lpwndpos->cy = m_rcSubItem.bottom;

    SubeditListView.cpp:
    old: m_editWnd.m_x = subrect.left + 6;
    new:
    m_editWnd.m_rcSubItem.left = subrect.left + 6;
    m_editWnd.m_rcSubItem.top = subrect.top;
    m_editWnd.m_rcSubItem.bottom = subrect.bottom - subrect.top;

    SIZE sz;
    CString cs(GetListCtrl().GetItemText(pDispInfo->item.iItem,m_subitem));
    ::GetTextExtentPoint32(m_editWnd.GetDC()->m_hDC, cs, cs.GetLength(), &sz);
    m_editWnd.m_rcSubItem.right = (sz.cx < 20 ? 20 : sz.cx); // or another min value

    Another tip:
    Forget about all the painting stuff. Just declare a CString
    member in SubEdit1.h to safe the original subitem text and
    empty this text. If the user cancels the operation just
    restore it from the CString member.

    Reply
  • ASSERT failure

    Posted by Legacy on 02/07/2003 12:00am

    Originally posted by: Luke Johnston

    When a lot of items are added, say 100, I get an ASSERT failure in wincore.cpp upon exiting the program.

    Any ideas?

    Reply
  • Thanks and bug

    Posted by Legacy on 01/28/2003 12:00am

    Originally posted by: Sylvain PEYRUQUEOU

    Thank you very much for your code, it was exactly what I need.

    However, I observe a bug when I click on a cell which is being edited. Is there anybody who has the same ?

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds