Easy Navigation Through an Editable List View | CodeGuru

Easy Navigation Through an Editable List View

First off, I would like to acknowledge that most of this code came from others at Code Guru. 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 […]

Written By
CodeGuru Staff
CodeGuru Staff
Jun 19, 1999
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

First off, I would like to acknowledge that most of this code came from others at Code Guru. 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;
}

Download demo application – 11 KB

History

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.