Q: How do I edit a list box item?
A: Individual items of a List box are not editable. How good it would have been, if each of the items are editable then and there! Here is a method to incorporate editing facility to the list box items where they are displayed.
You can't start editing of an item by single click of the mouse, since single click is reserved for selecting an item. One can open the editing session by many methods, by double clicking the item, by using any of the function keys (like F2) etc. In this method, I have used double click of mouse left button to initiate the editing. When I choose a different item of the list box, editing ends.
I derived my listbox class with editing facility CEditList from MFC class CListBox. I defined a variable m_Edit of type pointer to CEdit.
Code:
// In EditList.H
public:
CEdit* m_pEdit;
It is understood that when m_pEdit points to the edit object, if there is editing being performed or is equal to NULL when no editing is performed. The variable pEdit is initialised to NULL in CEditList constructor.
Code:
CEListBox::CEListBox()
{
m_pEdit = NULL;
}
In the constructor, I insert codes for deleting the edit pointer after use.
Code:
CEListBox::~CEListBox()
{
if (m_pEdit)
{
delete m_pEdit;
m_pEdit = NULL;
}
}
I created two member functions, first to start editing (InitEdit) and second to end the editing (EndEdit).
While starting the editing, I calculate which item to be edited from the information of mouse position. Then, the edit box is created and item copied to the edit box. For consistancy, font in edit box is matched with the list box.
Code:
void CEListBox::InitEdit(CPoint point)
{
// Gets current selection
int Index = GetCurSel();
if (Index != LB_ERR) // If there is a valid selection
{
// Gets item rectangle
CRect Rect;
GetItemRect(Index, Rect);
// Creats an edit box around the item
m_pEdit = new CEdit;
m_pEdit->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, Rect, this, WM_USER);
// Sets edit box font as display font of list box
m_pEdit->SetFont(GetFont());
// Copies item string to edit box
CString Text;
GetText(Index, Text);
m_pEdit->SetWindowText(Text);
}
}
In the function to end the editing, I copied the string of the edit box to the list box item and clears the pointer.
Code:
void CEListBox::EndEdit()
{
if (m_pEdit) // If editing is on
{
// Copies edit box text to item
CString Text;
m_pEdit->GetWindowText(Text);
int Index = m_pEdit->GetDlgCtrlID() - WM_USER;
// Changing of string is effectively deleting current atring
// And adding the modified string
DeleteString(Index);
InsertString(Index, Text);
// Deletes the edit box and points pointer to NULL
delete m_pEdit;
m_pEdit = NULL;
}
}
For starting the editing, I handle WM_LBUTTONDBLCLK mouse message to start editing of the item.
Code:
void CEListBox::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
InitEdit(point);
CListBox::OnLButtonDblClk(nFlags, point);
}
In the notification message function of changing the selection of the listbox (), I simply call EndEdit function to end the editing.
Code:
void CELBDlg::OnSelchangeList()
{
// TODO: Add your control notification handler code here
m_List.EndEdit();
}
I have attached a simple project of dialog box type, where the list box is of type CEditList.