Click here to Skip to main content
Licence CPOL
First Posted 20 Mar 2005
Views 113,194
Downloads 2,850
Bookmarked 61 times

Local Input With No Effort

By | 16 Oct 2009 | Article
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 :-))
  • 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

Member

More than 22 years of software development experience.
SCRUM Master nowadays

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 5 Pinmemberxuplus23:43 28 Jul '10  
GeneralRe: My vote of 5 PinmemberMircea Puiu4:37 23 May '11  
GeneralEnabling LVN_ENDLABELEDIT PinmembereFotografo6:05 9 Oct '09  
GeneralRe: Enabling LVN_ENDLABELEDIT PinmemberMircea Puiu21:47 9 Oct '09  
GeneralDebug ASSERT PinmembereFotografo7:29 8 Oct '09  
GeneralRe: Debug ASSERT PinmemberMircea Puiu2:30 9 Oct '09  
QuestionDoes not work with CListCtrl in a DialogBox PinmemberRLoe4:42 3 Sep '09  
AnswerRe: Does not work with CListCtrl in a DialogBox PinmemberMircea Puiu23:41 6 Sep '09  
GeneralRe: Does not work with CListCtrl in a DialogBox PinmemberRLoe12:49 7 Sep '09  
GeneralRe: Does not work with CListCtrl in a DialogBox PinmemberMircea Puiu2:36 15 Oct '09  
GeneralStill Assert Pinmemberdomgom12:18 20 Jun '06  
GeneralLimiting use of this class Pinmemberjouwpaard1:32 11 May '06  
GeneralRe: Limiting use of this class PinmemberMircea Puiu4:41 11 May '06  
GeneralRe: Limiting use of this class Pinmemberjouwpaard7:27 11 May '06  
GeneralRe: Limiting use of this class PinmemberMircea Puiu7:49 11 May '06  
GeneralCListBox Pinmemberwurstberg23:02 27 Jan '06  
GeneralRe: CListBox PinmemberMircea Puiu8:07 28 Jan '06  
GeneralRe: CListBox Pinmemberhanno252:40 30 Jan '06  
GeneralRe: CListBox PinmemberMircea Puiu5:23 15 Feb '06  
GeneralDisable ClistCtrl Pinmembermbks4:48 19 Jul '05  
GeneralRe: Disable ClistCtrl PinmemberMircea Puiu5:50 19 Jul '05  
GeneralTHANKS Pinmemberafelsan1:59 15 Jul '05  
GeneralRe: THANKS PinmemberMircea Puiu5:51 19 Jul '05  
GeneralI'm not alone! Pinmemberaraud18:31 31 Mar '05  
GeneralRe: I'm not alone! PinmemberMircea Puiu20:17 31 Mar '05  

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.

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