Click here to Skip to main content
15,888,816 members
Articles / Desktop Programming / MFC
Article

Simple Listbox In-place Editing

Rate me:
Please Sign up or sign in to vote.
4.15/5 (13 votes)
20 Feb 2001 174.4K   2.2K   41   26
A edit window which greatly simplifies in-place editing of listbox lines

Sample Image - lbed.gif

Introduction

Here's a simple class to make it easy to edit list box entries in place. It isn't derived from CListBox, but instead from CEdit and designed to work with CListBox.

Design Philosophy

First a word about the design philosophy that lead to this simple class. A new edit window is created everytime you edit and item and destroyed when you're done. In the past, I'd probably would have created the edit window once, then move it, show it, hide it etc. as needed. Why, I thought, take on the overhead of window creation and destruction over and over instead of just once?

Here's why: because its simpler and the potential performance gains you get just don't matter. CLBEditorWnd has 9 member functions, many of them trivial and the longest one is less than 20 lines of non-comment code. The whole class, including header file and comments is under 300 lines. Adding it to the sample project took <10 lines of code. This simplicity makes code much more understandable and is valuable.

Don't get me wrong. Having a responsive UI is really important, but you don't get that by caching windows and fonts and other GDI resources and reusing them whenever possible. In some cases, the OS even does the caching for you. But even if it doesn't, other design decisions have a much more substantial impact on responsiveness.

Are you making numerous synchronous calls to a database server inside the message loop? That's going to hurt responsiveness. Are you doing a lot of complex rendering in OnDraw()? Don't. Use on off-screen blit map and only do the blitting in OnDraw(). Use worker threads liberally.

I could continue this digression to discuss how many threads is too many, but I'm getting farther afield than I planned already. Use common sense. Now, back to the business at hand.

Using CLBEditorWnd

CLBEditorWnd can be used with a two-line sequence:

CLBEditorWnd* pEditor = new CLBEditorWnd( &list_control_to_edit ) ;
pEditor->Edit( index_of_item_to_edit ) ;
That's it. CLBEditorWnd cleans up after itself, so even though you orphan the pointer, there will be no memory leak. When its done, CLBEditorWnd will update the listbox with whatever changes are made unless the user hits the escape key.

How it works

Most of the work is done in two member functions Edit() and EndEditing().

bool CLBEditorWnd::Edit(
		int n		// @parm Index of item in list box to edit
	)
{
    if ( n < 0 || n >= m_pLB->GetCount() )
	{
		delete this ;
		return false ;
	}

	m_edit_index = n ;

	CString s ;
	m_pLB->GetText( n, s ) ;

	CRect r ;
	m_pLB->GetItemRect( n, &r ) ;
	r.InflateRect( 1, 1 ) ;

	Create( WS_BORDER | WS_CHILD | WS_VISIBLE | ES_WANTRETURN, r, m_pLB, 1 ) ;
	SetFont( m_pLB->GetFont()) ;

	SetWindowText( s ) ;
	SetCapture() ;
	SetFocus() ;

	return true ;
}
First Edit() grabs the text and rectangle of the listbox item and uses that as the CLBEditorWnd text and rectangle. It creates the window, sets focus and capture to itself and returns to let the standard message pump do its stuff.

void CLBEditorWnd::EndEditing(
		bool b		// @parmopt bool | b | true | If true, the list box item is updated
	)
{
	if ( m_edit_ended )
		return ;

	m_edit_ended = true ;
	ReleaseCapture() ;
	if (b )
	{
		CString s ;
		GetWindowText( s ) ;

		m_pLB->DeleteString( m_edit_index ) ;
		m_pLB->InsertString( m_edit_index, s ) ;
		m_pLB->SetCurSel( m_edit_index ) ;
	}

	MSG msg ;
	while ( ::PeekMessage( &msg, m_hWnd, 0, 0, PM_REMOVE ) )
		;

	DestroyWindow() ;
}

At some point, EndEditing() is called by some boring MFC message handling function. It releases the mouse and (usually) replaces the appropriate item in the list box. Everything else is just housekeeping, including delete this in the WM_NCDESTROY handler.

One quirk that CLBEditorWnd has to deal with involves message routing. Because changes of focus to another app with alt-Tab and the like give the window no other notice than a kill focus message, I had to use that as a reason to call EndEditing(). But other actions cause EndEditing() too, and indirectly cause loss of focus potentially causing EndEditing() to be called twice, once after the object is deleted.

Obviously, this won't do. So EndEditing() includes a PeekMessage() loop to remove any unprocessed messages for the window. Doesn't matter, somewhere inside the PeekMessage() call, the kill focus notification is generated and processed before I have a chance to delete it. So there's a recursion prevention flag added to the class as well.

Any drawbacks?

As written, it works only with listboxes, not list controls, tree controls or anything else. Modifying the code to deal with those other types should be fairly easy. It also doesn't handle edit commands from the menu bar -- you can use the context menu to cut/copy/paste and the accelerator keys seem to work, but unless you take steps to enable the menu items in your app, and route the commands appropriately, you can't use the menu bar.

It does provide what I need at the moment, a simple and effective way to edit list box items in place.

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
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalnotifying the parent that a change has taken place Pin
garaber20-Apr-11 8:12
garaber20-Apr-11 8:12 
QuestionSetFocus and Set Capture do not appear to be holding for this source set any ideas Pin
garaber20-Apr-11 5:15
garaber20-Apr-11 5:15 
AnswerRe: SetFocus and Set Capture do not appear to be holding for this source set any ideas Pin
garaber20-Apr-11 5:32
garaber20-Apr-11 5:32 
GeneralES_AUTOHSCROLL Pin
hf_blueideal2-Feb-07 1:46
hf_blueideal2-Feb-07 1:46 
you may add ES_AUTOHSCROLL to Create() in CLBEditorWnd::Edit(), so that the edit can auto scroll
QuestionHow to destroy Edit Box Pin
Mahendra Chuttar12-Sep-06 2:32
Mahendra Chuttar12-Sep-06 2:32 
AnswerRe: How to destroy Edit Box Pin
scrat_amir1-Dec-07 9:00
scrat_amir1-Dec-07 9:00 
GeneralGetWindowInfo error solution Pin
remur21-Feb-06 2:25
remur21-Feb-06 2:25 
GeneralCListCtrl-&gt;GetItemPosition Pin
asahrawat28-Jul-04 20:00
asahrawat28-Jul-04 20:00 
GeneralCListCtrl-&gt;GetItemPosition Pin
asahrawat28-Jul-04 20:00
asahrawat28-Jul-04 20:00 
GeneralRe: CListCtrl-&gt;GetItemPosition Pin
rolfneumann20-Oct-04 1:48
rolfneumann20-Oct-04 1:48 
GeneralError in CListCtrl HitTest Pin
asahrawat26-Jul-04 23:45
asahrawat26-Jul-04 23:45 
GeneralError WINDOWINFO structure Pin
asahrawat22-Jul-04 23:59
asahrawat22-Jul-04 23:59 
GeneralRe: Error WINDOWINFO structure Pin
Christian Graus19-Oct-06 7:03
protectorChristian Graus19-Oct-06 7:03 
GeneralError in GetWindowInfo Pin
asahrawat22-Jul-04 23:56
asahrawat22-Jul-04 23:56 
GeneralCLBEditorWnd::EndEditing() missing feature... Pin
Luc Bergeron8-Jan-04 7:53
Luc Bergeron8-Jan-04 7:53 
GeneralListBox with "edit labels" style in MFC Pin
21-Jun-01 19:54
suss21-Jun-01 19:54 
GeneralRe: ListBox with "edit labels" style in MFC Pin
Chris Losinger9-Feb-03 11:12
professionalChris Losinger9-Feb-03 11:12 
GeneralRe: ListBox with "edit labels" style in MFC Pin
Anonymous27-Mar-03 16:24
Anonymous27-Mar-03 16:24 
GeneralRe: ListBox with &quot;edit labels&quot; style in MFC Pin
alex.barylski4-May-04 8:39
alex.barylski4-May-04 8:39 
GeneralRe: ListBox with "edit labels" style in MFC Pin
enfoiros31-Mar-03 20:39
enfoiros31-Mar-03 20:39 
GeneralGetWindowInfo() Pin
22-Apr-01 18:31
suss22-Apr-01 18:31 
GeneralRe: GetWindowInfo() Pin
asahrawat25-Jul-04 22:57
asahrawat25-Jul-04 22:57 
GeneralUnexpected behaviour Pin
22-Apr-01 18:20
suss22-Apr-01 18:20 
GeneralRe: Unexpected behaviour Pin
Anonymous23-Oct-02 22:15
Anonymous23-Oct-02 22:15 
QuestionMissing 'break'? Pin
Joseph M. Newcomer14-Feb-01 6:58
Joseph M. Newcomer14-Feb-01 6:58 

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.