Click here to Skip to main content
Click here to Skip to main content

Local Input With No Effort

, 16 Oct 2009
Rate this:
Please Sign up or sign in to vote.
A sort of "add-on" to any application, which does not change at all the behaviour of the application but solves the "local edit" problem in a unitary way.
Sample Image

Introduction

A lot of approaches have been made in order to improve MFC classes like CListCtrl (report - style), CListBox, or even CTreeCtrl (even though the last one allows for label editing), in the sense of allowing the user to edit their items "in-line". Those approaches are very elaborate, and require a lot of care to be taken when coming to treating as many of their events as possible in order to prevent unwanted behaviours. When trying to improve older applications, a user has to replace the declarations of his / her objects with new ones related to the provided derived classes, and should test the applications extensively against possible unwanted "features".

What if a class - a single one - would allow the modification, on an item base, of all the CListCtrl, CListBox, CTreeCtrl, and even the CComboBox (after all, the last class makes use of CListBox) objects of an application without changing the object declarations and disregarding the style combinations that may apply to some or all of the objects?

Note: After the updates dated March 23, the content of the list box used by the CComboBox control is visible while doing the local input.

combo image

The LocalInputDlg comes as a sort of "add-on" to any application, it does not change the behaviour of the application at all but solves the "local edit" problem in a unitary way. Try this class and you will add only two lines of code to your application. In return, a right-click on items belonging to objects of the above mentioned type will offer you the possibility to locally edit them.

Using the LocalInputDlg

Here are the steps you have to follow to add the "local edit" functionality to your beloved application:

  1. Add LocalInputDlg.h and LocalInputDlg.cpp files to your project.
  2. Uncomment the LIWNE_USE_LVN_ENDLABELEDIT in LocalInputDlg.h if you handle the LVN_ENDLABELEDIT notification in your application.
  3. Include LocalInputDlg.h in YourApp.h.
  4. Use the wizard to add the PreTranslateMessage() virtual function to YourApp.cpp.
    1. Add the LocalInputDlg dlgInput member to YourApp class.
    2. Inside the generated function, write the following line of code, exactly after the TODO remark line:
      if (dlgInput.DoLocalInput(pMsg, true)) return TRUE;

      should the chosen style be "arrow", or:

      if (dlgInput.DoLocalInput(pMsg, false)) return TRUE;

      for the "in-line" style.

That's all! Compile your project and here you are!

The Things Behind

In its OnInitDialog() function, LocalInputDlg positions itself depending on the position of the clicked item, and positions and resizes its controls accordingly. The width of the input field reflects the current width of the item. The window region is set so that the dialog gets either the "arrow" style or the "in-line edit" style aspect.

The local edit process starts by calling the DoLocalInput() with a MESSAGE pointer, provided by the PreTranslateMessage() function of the application, as parameter. The DoLocalInput() function checks if it deals with a WM_RBUTTONDOWN (other messages can be used in place). In the case of this message, the function decides the way the message is to be processed. The pMsg->hwnd handle is used to get a pointer to the window posting the message, which is type-cast to a CListBox* pointer. Let this pointer be pLB. With pLB->GetCount() returning a positive number, the function decides it is dealing with a CListBox object (this is also the case of the CComboBox, as the message is coming from a temporary window which, in fact, is a CListBox). Otherwise, the function gets the run-time class of the window posting the message (in the previous decision making, this was not working, as the window was temporary). Should the run-time class be a CTreeCtrl, the function deals with a CTreeCtrl object. Should the run-time class be a CListCtrl, the function deals with a CListCtrl object. Depending on the decision made, the appropriate request processing function is called.

    ProcessInputRequest(CListBox  *pLB,   CPoint point);
    ProcessInputRequest(CListCtrl *pLC,   CPoint point);
    ProcessInputRequest(CTreeCtrl *pTree, CPoint point);

Each of these functions estimates the position of the hit item and invokes the modal LocalInputDlg.

Supporting the LVN_ENDLABELEDIT Notification for list-view Controls

eFotografo made a good point (see his message in the FAQ section below). In case of CListCtrl objects, the corresponding ProcessInputRequest() processing function needs to send a WM_NOTIFY message to control's parent, so that LVN_ENDLABELEDIT can be handled, if the application is needed to decide whether to accept or not the modification in the list-view (input validation).
NMLVDISPINFO nminfo;
nminfo.hdr.code = LVN_ENDLABELEDIT;
nminfo.hdr.hwndFrom = pLC->GetSafeHwnd();
nminfo.hdr.idFrom = pLC->GetDlgCtrlID();
nminfo.item.iItem = info.iItem;
nminfo.item.iSubItem = info.iSubItem;
nminfo.item.pszText = m_strInput.GetBuffer(0);
nminfo.item.mask = LVIF_TEXT;
if (pLC->GetParent()->SendMessage(WM_NOTIFY, (WPARAM)IDDLOCALEDIT, 
	(LPARAM)(LPNMHDR)&nminfo))
{
    pLC->SetItemText(info.iItem, info.iSubItem, m_strInput.GetBuffer(0));
}

Depending on the value returned by SendMessage(WM_NOTIFY), the text in the list cell is modified according to the user input or the modification is rejected. This value (either 1 or 0) is decided within the handler for the LVN_ENDLABELEDIT notification:

void YourAppDlg::YourHandlerFor_LVN_ENDLABELEDIT (NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    CString itemtext(pDispInfo->item.pszText); // do something with it
    *pResult = TRUE; // accept the changes
    MessageBox((LPCTSTR)pDispInfo->item.pszText, 
		(LPCTSTR)"Accepted input"); // testing only
}

combo image

void YourAppDlg::YourHandlerFor_LVN_ENDLABELEDIT (NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    CString itemtext(pDispInfo->item.pszText); // do something with it
    *pResult = FALSE; // reject the changes
    MessageBox((LPCTSTR)pDispInfo->item.pszText, 
		(LPCTSTR)"Accepted input"); // testing only
}

combo image

In case no validation action is taken in the application using the LVN_ENDLABELEDIT notification mechanism, i.e. no entry is provided in the message map of application's dialog:

BEGIN_MESSAGE_MAP(YourAppDlg, CDialog)
	//{{AFX_MSG_MAP(YourAppDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	<s>ON_NOTIFY(LVN_ENDLABELEDIT, .....)</s>
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

pLC->GetParent()->SendMessage(WM_NOTIFY) in the ProcessInputRequest() code for CListCtrl always returns 0 and LocalInputDlg loses functionality. For that reason, the LIWNE_USE_LVN_ENDLABELEDIT preprocessor variable is used in LocalInputDlg.h:

#ifndef LIWNE_USE_LVN_ENDLABELEDIT
//#define LIWNE_USE_LVN_ENDLABELEDIT
#endif

The header file comes with this definition commented out, assuming the LVN_ENDLABELEDIT event is not handled in your application. Please uncomment it should your application handle that event. The presence of that preprocessor variable turns on the code in ProcessInputRequest() for CListCtrl related to input validation. By removing it, the previously mentioned code is turned off and the pLC-> SetItemText(info.iItem, info.iSubItem, m_strInput.GetBuffer(0)) is always called to accomplish the local editing of the list-view cell.

History

  • Created: March 21, 2005
  • Updated: March 23, 2005, due to the welcome request of jdmulder and the excellent ideas of PJ Arends. Code lines not belonging to the author are marked as "courtesy of ...".
  • Updated: April 5, 2005 - support for "arrow" style and "in-line" style
  • Updated: March 10, 2006 - article content correction in the section "Using the LocalInputDlg 4.b.": dlgInput.DoLocalInput(pMsg,...) instead of dlgInput(pMsg,...) (fortunately, the source code is ok Smile | :) )
  • Updated: October 16, 2009 - VS2005 source code and LVN_ENDLABELEDIT notification support added, as a result of eFotografo's excellent remarks

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mircea Puiu
Software Developer (Senior)
Europe Europe
More than 22 years of software development experience.
SCRUM Master nowadays

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberxuplus28-Jul-10 23:43 
GeneralRe: My vote of 5 PinmemberMircea Puiu23-May-11 4:37 
GeneralEnabling LVN_ENDLABELEDIT PinmembereFotografo9-Oct-09 6:05 
GeneralRe: Enabling LVN_ENDLABELEDIT PinmemberMircea Puiu9-Oct-09 21:47 
GeneralDebug ASSERT PinmembereFotografo8-Oct-09 7:29 
GeneralRe: Debug ASSERT PinmemberMircea Puiu9-Oct-09 2:30 
QuestionDoes not work with CListCtrl in a DialogBox PinmemberRLoe3-Sep-09 4:42 
AnswerRe: Does not work with CListCtrl in a DialogBox PinmemberMircea Puiu6-Sep-09 23:41 
GeneralRe: Does not work with CListCtrl in a DialogBox PinmemberRLoe7-Sep-09 12:49 
GeneralRe: Does not work with CListCtrl in a DialogBox PinmemberMircea Puiu15-Oct-09 2:36 
GeneralStill Assert Pinmemberdomgom20-Jun-06 12:18 
GeneralLimiting use of this class Pinmemberjouwpaard11-May-06 1:32 
GeneralRe: Limiting use of this class PinmemberMircea Puiu11-May-06 4:41 
GeneralRe: Limiting use of this class Pinmemberjouwpaard11-May-06 7:27 
GeneralRe: Limiting use of this class PinmemberMircea Puiu11-May-06 7:49 
GeneralCListBox Pinmemberwurstberg27-Jan-06 23:02 
GeneralRe: CListBox PinmemberMircea Puiu28-Jan-06 8:07 
GeneralRe: CListBox Pinmemberhanno2530-Jan-06 2:40 
GeneralRe: CListBox PinmemberMircea Puiu15-Feb-06 5:23 
GeneralDisable ClistCtrl Pinmembermbks19-Jul-05 4:48 
GeneralRe: Disable ClistCtrl PinmemberMircea Puiu19-Jul-05 5:50 
GeneralTHANKS Pinmemberafelsan15-Jul-05 1:59 
GeneralRe: THANKS PinmemberMircea Puiu19-Jul-05 5:51 
GeneralI'm not alone! Pinmemberaraud31-Mar-05 18:31 
GeneralRe: I'm not alone! PinmemberMircea Puiu31-Mar-05 20:17 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 16 Oct 2009
Article Copyright 2005 by Mircea Puiu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid