Click here to Skip to main content
15,867,771 members
Articles / Desktop Programming / MFC
Article

Easy Navigation Through an Editable List View

Rate me:
Please Sign up or sign in to vote.
4.78/5 (16 votes)
19 Jun 2000 207.5K   2.1K   71   22
This article shows you how you can navigate through a multi-column, editable list view
  • Download source files - 30 Kb
  • Download demo project - 10 Kb
  • Sample Image - ListEditor.jpg

    Introduction

    First off, I would like to acknowledge that most of this code came from others at CodeGuru. I took code from some of the articles submitted by Zafir Anjum, so look at his article "Editable Subitems" as a basis for this article.

    This project demonstrates how the list view/control can be used to edit information in the form of a table (multiple-editable columns). I have captured the Tab, Page Down, Page Up, Up, Down, Home, and End keys to allow easy navigation through the control.

    As shown in "Editable Subitems", I subclassed the CEdit control with my class called gxEditCell. Then, I added a new parameter to it's constructor. This new parameter is a pointer to the parent list control so that my edit box could inform the list control of any important events, like a key press. Then when I get a key event, I simply tell the list control which subitem I want to edit next based off the current cell that is being edited. This can be seen in the OnKeyDown function below. As you can see, when I receive the VK_UP key event, I am telling the list control to edit the subitem located directly above the current cell. I check, of course, to see if it is a valid cell first.

    The reason I caught some events in the KeyDown, some in the KeyUp, and some in the OnChar, had to do with how the application behaved. If I would have caught the VK_PRIOR or VK_NEXT in the OnKeyDown, I would get several calls depending on how long the button was pressed. This is very annoying. If you don't believe me, move the code, add several items to the list and try it (it isn't pretty).

    I also caught the ESC key so that I could cancel an edit. The return key is being used to end an edit and when it is on the last record, it insert a new one. Just don't forget to override the OnGetDlgCode() so that you can get the arrow keys and tabs.

    gxEditCell::gxEditCell (gxListCtrl* pCtrl, int iItem, int iSubItem, CString sInitText)
    :   bEscape (FALSE)
    {
        pListCtrl = pCtrl;
        Item = iItem;
        SubItem = iSubItem;
        InitText = sInitText;
    }
    
    void gxEditCell::OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
        // Up and down are in the OnKeyDown so that the user can hold down the arrow
        // keys to scroll through the entries.
        BOOL Control = GetKeyState (VK_CONTROL) < 0;
        switch (nChar)
        {
    		case VK_UP :
    		{
    			if (Item > 0)
    				pListCtrl->EditSubItem (Item - 1, SubItem);
    			return;
    		}
    		case VK_DOWN :
    		{
    			pListCtrl->EditSubItem (Item + 1, SubItem);
    			return;
    		}
    		case VK_HOME :
    		{
    			if (!Control)
    				break;
    
    			pListCtrl->EditSubItem (0, SubItem);
    			return;
    		}
    		case VK_END :
    		{
    			if (!Control)
    				break;
    
    			int Count = pListCtrl->GetItemCount() - 1;
    			pListCtrl->EditSubItem (Count, SubItem);
    			return;
    		}
        }
        
        CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
    }
    
    void gxEditCell::OnKeyUp (UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
        switch (nChar)
        {
    		case VK_NEXT :
    		{
    			int Count = pListCtrl->GetItemCount();
    			int NewItem = Item + pListCtrl->GetCountPerPage();
    			if (Count > NewItem)
    				pListCtrl->EditSubItem (NewItem, SubItem);
    			else
    				pListCtrl->EditSubItem (Count - 1, SubItem);
    			return;
    		}
    		case VK_PRIOR :
    		{
    			int NewItem = Item - pListCtrl->GetCountPerPage();
    			if (NewItem > 0)
    				pListCtrl->EditSubItem (NewItem, SubItem);
    			else
    				pListCtrl->EditSubItem (0, SubItem);
    			return;
    		}
        }
        
        CEdit::OnKeyUp (nChar, nRepCnt, nFlags);
    }
    
    void gxEditCell::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
        BOOL Shift = GetKeyState (VK_SHIFT) < 0;
        switch (nChar)
        {
    		case VK_ESCAPE :
    		{
    			if (nChar == VK_ESCAPE)
    				bEscape = TRUE;
    			GetParent()->SetFocus();
    			return;
    		}
    		case VK_RETURN :
    		{
    			SetListText();
    			pListCtrl->EditSubItem (Item + 1, 0);
    			return;
    		}
    		case VK_TAB :
    		{
    			if (Shift)
    			{
    				if (SubItem > 0)
    					pListCtrl->EditSubItem (Item, SubItem - 1);
    				else
    				{
    					if (Item > 0)
    						pListCtrl->EditSubItem (Item - 1, 2);
    				}
    			}
    			else
    			{
    				if (SubItem < 2)
    					pListCtrl->EditSubItem (Item, SubItem + 1);
    				else
    					pListCtrl->EditSubItem (Item + 1, 0);
    			}
    			return;
    		}
        }
    
        CEdit::OnChar (nChar, nRepCnt, nFlags);
    
        // Resize edit control if needed
    
        // Get text extent
        CString Text;
    
        GetWindowText (Text);
        CWindowDC DC (this);
        CFont *pFont = GetParent()->GetFont();
        CFont *pFontDC = DC.SelectObject (pFont);
        CSize Size = DC.GetTextExtent (Text);
        DC.SelectObject (pFontDC);
        Size.cx += 5;			   	// add some extra buffer
    
        // Get client rect
        CRect Rect, ParentRect;
        GetClientRect (&Rect);
        GetParent()->GetClientRect (&ParentRect);
    
        // Transform rect to parent coordinates
        ClientToScreen (&Rect);
        GetParent()->ScreenToClient (&Rect);
    
        // Check whether control needs to be resized and whether there is space to grow
        if (Size.cx > Rect.Width())
        {
    		if (Size.cx + Rect.left < ParentRect.right )
    			Rect.right = Rect.left + Size.cx;
    		else
    			Rect.right = ParentRect.right;
    		MoveWindow (&Rect);
        }
    }
    
    UINT gxEditCell::OnGetDlgCode() 
    {
        return CEdit::OnGetDlgCode() | DLGC_WANTARROWS | DLGC_WANTTAB;
    }

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    Web Developer
    Canada Canada
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    QuestionUsing the code in our commercial product Pin
    sangyeun1-Nov-15 14:09
    sangyeun1-Nov-15 14:09 
    GeneralMy vote of 5 Pin
    maplewang4-Aug-12 4:21
    maplewang4-Aug-12 4:21 
    GeneralUsing the code in our commercial product Pin
    Prakash Buddhiraja11-Mar-09 13:04
    Prakash Buddhiraja11-Mar-09 13:04 
    GeneralScroll Problem Pin
    MartinK29-Jun-06 1:05
    MartinK29-Jun-06 1:05 
    GeneralCListCtrl Navigation Pin
    Manoj Singh K.19-Oct-04 3:52
    Manoj Singh K.19-Oct-04 3:52 
    GeneralCool Pin
    Patrik Svensson1-Aug-04 0:54
    Patrik Svensson1-Aug-04 0:54 
    Really nice piece of code.
    Keep up the good work!


    "If knowledge can create problems, it is not through ignorance that we can solve them."
    Isaac Asimov
    GeneralProblem with scrolling Pin
    Member 41032715-Feb-04 2:34
    Member 41032715-Feb-04 2:34 
    GeneralAlignment of Rebar Pin
    Member 2224466-Dec-03 6:13
    Member 2224466-Dec-03 6:13 
    Generalwhen columns over 3 Pin
    jack tian18-Jun-03 17:31
    jack tian18-Jun-03 17:31 
    GeneralStrange behaviour in Win98 Pin
    Dudi Avramov18-Feb-03 20:56
    Dudi Avramov18-Feb-03 20:56 
    GeneralRe: Strange behaviour in Win98 Pin
    Dudi Avramov19-Feb-03 2:25
    Dudi Avramov19-Feb-03 2:25 
    GeneralWEW Pin
    Anonymous11-Jan-03 20:15
    Anonymous11-Jan-03 20:15 
    Generalbit long.. Pin
    Bengi14-Sep-02 13:24
    Bengi14-Sep-02 13:24 
    GeneralRe: bit long.. Pin
    armentage27-Sep-02 7:35
    armentage27-Sep-02 7:35 
    GeneralEasy navigation - CListCtrl example Pin
    john john mackey9-Oct-01 11:28
    john john mackey9-Oct-01 11:28 
    GeneralRe: Easy navigation - CListCtrl example Pin
    john john mackey9-Oct-01 12:03
    john john mackey9-Oct-01 12:03 
    GeneralTab through list Control Pin
    Vineet Luktuke13-Jul-01 5:57
    Vineet Luktuke13-Jul-01 5:57 
    GeneralCapturing Item... Pin
    26-Jun-01 12:24
    suss26-Jun-01 12:24 
    GeneralProblems with caret's visibility Pin
    25-Mar-01 20:48
    suss25-Mar-01 20:48 
    GeneralProblems with ES_RIGHT Pin
    13-Mar-01 21:16
    suss13-Mar-01 21:16 
    GeneralRe: Problems with ES_RIGHT Pin
    DanYELL23-Jun-04 7:58
    DanYELL23-Jun-04 7:58 
    GeneralEditable length Pin
    22-Nov-00 1:24
    suss22-Nov-00 1:24 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.