Solved

CListCtrl selection change

Posted on 2000-05-06
14
1,871 Views
Last Modified: 2013-11-20
Quite a basic question:
Is there any elegant way of determining that the selection change in the CListCtrl was caused by the user not from the program?
The OnItemChanged handler is called in both cases. I tried to determine it based on focus changes and also using LVN_ITEMACTIVATE message, but with no success.
0
Comment
Question by:ewajoz
  • 6
  • 4
  • 4
14 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 2784630

Here's your fn to set the selection programmatically:
-=-=-=-=-=-=-=-=-=-=-=-
BOOL SetSelItemIdx( CListCtrl& cCtlList, int nItmIdx )
{
  LVITEM lvi;
  lvi.stateMask = LVIS_SELECTED | LVIS_FOCUSED | 0x40;
  lvi.state =     LVIS_SELECTED | LVIS_FOCUSED | 0x40;
      return (BOOL) ::SendMessage(cCtlList.m_hWnd, LVM_SETITEMSTATE, nItmIdx, (LPARAM)&lvi);
}
-=-=-=-=-=-=-=-=-=-=-=-
Here's your onchange handler:
-=-=-=-=-=-=-=-=-=-=-=-
void CJunkDlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  if  (pNMListView->uNewState & 0x40 ) {
    MessageBox("program changed it" );
  }
  *pResult = 0;
}
-=-=-=-=-=-=-=-=-=-=-=-
ox40 is the first unused state bit (see Commctrl.h) You might choose a higher bit to avoid some problems with future changes or maybe use LVIS_ACTIVATING which the dox say is not used -- but was possibly originally intended for this purpose)



0
 
LVL 1

Accepted Solution

by:
MT_MU earned 100 total points
ID: 2785076
Alternatively...

Include a BOOL variable in your class that's working with the list ctrl...

BOOL m_bLockOut;

In the functions that are manipulating the listctrl set m_bLockOut = TRUE; and rest it when done.


In the OnItemChanged() function

if (!m_bLockOut)
{
  // know to be a user change.
}

0
 

Author Comment

by:ewajoz
ID: 2796148
This what I am actually doing. I just thought there might a better way.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 2797101
Dear ewajoz,
Will you comment on the fact that I provided you an elegant way to perfom the desired function, yet you selected MT_MU's inelegant answer (one which I (and you) rejected immediately as a sort of kludge?)

I'm puzzled. and irritated.

thanks
0
 

Author Comment

by:ewajoz
ID: 2799311
Dear DanRollins,
I am in despair that you took my choice in this way.
The problem is that I could not pass my points to both of you, which I would have loved to do, as I appreciate both answers equally. The reason of my choice was that I have given you my points for the other listctrl selection problem and so decided to award MT_MU this time.

Actually, I consider both yours and MT_MU's solutions as not the most elegant, but the only possible as the list control apparently misses this functionality. As I wrote I am using MT_MU's one. Yours seem more original, I admit, but also more dangerous. Thus I do not intend to switch to it, unless you convince me that I should.

Looking forward to hearing from you, with best regards,
ewajoz.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 2801945
hi ewajoz,
In addition to being a kludge, MT_MUs answer is incomplete, and could conceivably fail in a way that would be hard to debug (probably 2 days before production drop-dead date).  Example:

If an external action causes a list item to be selected near the same time that a user clicks, the m_bLockOut would be true and the wrong event would be handled as a "programatic selection" and the other event -- which should have been handled that way -- is treated as a user-click selection.

This happens in a program I wrote: When the program receives data from the COMM port (on another thread), it automatically inserts an item in my Tree View and selects it, forcing related data to be displayed in a Data View. A simultaneous click in the Tree View could cause serious problems.

It's the kind of rarely-occurring bug that one learns to prevent using defensive programming techniques like this --- "hmmm, I if set a global flag variable, what would happen if..."

On the other hand, if you plan to select the list item programatically only in the InitDialog() handler or such, then there's probably no cause for alarm.  Even so, you question was specific: "...any elegant way..."

Furthermore, just because I answered another unrelated question is hardly a reason ro deny me points.  It's like my boss saying "well you did real good this week, but I paid you for the work you did last week, so... sorry, no paycheck this week for danny boy!"

regards,
-- dan

0
 
LVL 1

Expert Comment

by:MT_MU
ID: 2802051
Hey Dan....

I feel obligated to chime in here.

Sorry you view my answer as a kludge, but I'm hardly enamored with yours either.

You are relying on "undocumented" behavior.

Re:>>  "ox40 is the first unused state bit (see Commctrl.h) You might choose a higher bit to avoid some problems with future changes or maybe use LVIS_ACTIVATING which the dox say is not used -- but was possibly originally intended for this purpose)"


FWIW - You'll get to 5k points quick enough without disparaging others answers.






0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 49

Expert Comment

by:DanRollins
ID: 2805975
Sorry MT_MU,

My comment was not intended as a disparagement of your solution.  It was an in-depth analysis of a possible problem that could arise if it were to be used.  It was in response to ewajoz's comment that yours was the safer method (which it clearly is not).

When I said that your solution was incomplete, I was referring to the fact that you failed to mention when to reset m_bLockOut and did not show it in your example.  As given, your answer would cause ewajoz's program to think that all list selections were programmatic.

What's more, you poached.  You presented an incomplete answer, some seven hours after I presented a complete and elegant answer.  I have a clear right to defend my answer and  ask why your answer was chosen, don't I?

As to your point that my solution was undocumented.  You are right.   So is my function that sets the selection (MFC does not provide a simple SetSel() member nor does the ClassWizard provide DDX support -- one needs to turn to the API, which is what I did).

Of course, nobody like to see their code called a kludge, so I fully understand your position.

-- dan
0
 

Author Comment

by:ewajoz
ID: 2806235
Dan
thank you for pointing out that the flag approach mail fail in some rare cases. Perhaps I will think of using yours. However, none is ideal...

As to my choice: It is left to the questionner subjective opinion which answer to choose. It might happen that other people do not agree with it or feel unhappy as you do. I made the choice that I consider best. However, as I wrote I was not entirely happy with it and still would happilly award both of you. Can you think of how to do it? Write the Webmaster? Is there any other way to make you happier?

Finally, I must admit that me too was struck by the unpolite form of presenting you reservations. It did not help me to accept them.

Regards, Ewa.

P.s. I might not have internet access during the weekend.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 2806367
Ewa,
You are right in every respect.  Forgive me for making too much of this.  There is no need for further action of any type.

-- dan
0
 
LVL 1

Expert Comment

by:MT_MU
ID: 2807247
In the interest of completeness for anyone that would use their points to read this exchange - I feel compelled to make a couple of points.

First - re the "undocumented" aspect of Dans proposed solution.

There is a difference between MFC not providing a SetSel() function - and using a bit flag that "is" undocumented.  Obviously the method to set selections is documented, and bits that represent states "are" defined.  Some bits are "not" used - hence they are "undocumented".

Why should you care?  Good question, say your application is a commercial one, and it achieves even moderate success - 10's of thousands of users.  Now imagine that Microsoft decides to use the "bit" that you selected in the next version of comctl.  Your application breaks because you relied on that particular bit remaining "undocumented".  

Second - re the propensity to fail comparison...

Consider the following...

First in a single threaded app...

void CMyClass::DoSomeChangeofState(...)
{
  m_bLockOut = TRUE;
  // code to manipulate the state
  m_bLockOut = FALSE;
}

void CMyClass::OnItemchangedList(....)
{
  if (m_bLockOut)
  {
    // Program changed - handle appro
  }
  else
  {
    // User selection - ditto
  }
}

There are two possibilities here - depending on whether you use SendMessage or PostMessage to change the "state".

Normally (or at least normal for me) I use SendMessage in this situation. MFC in it's implementation for controls also uses SendMessage.  In this case there is only one thread - and only one possible path of execution - there is no possible way that this can fail.

If you used PostMessage - then it can and probably will fail.  But not in the way that Dan described.

The order of things would be...

DoSomeChangeofState >> set m_bLockOut
DoSomeChangeofState >> Posts Message
DoSomeChangeofState >> resets m_bLockOut
PostMessage gets handled.

Hence, OnItemChangedList would never see m_bLockOut = TRUE;

Now for the case where multiple threads are accessing the control...

In this case you are required to have a mechanism to control access to the listcontrol anyway, correct?  So you have essential a single thread version, since only one thread can "touch" the listctrl at a time.  

void CMyClass::DoSomeChangeofState(...)
{
  // Code to synchronize the threads
  // via a mutex or other method

  m_bLockOut = TRUE;
  // code to manipulate the state
  m_bLockOut = FALSE;

  // Code to release the mutex, etc.
}



0
 
LVL 49

Expert Comment

by:DanRollins
ID: 2807451
Thank you MT_MU for your clarification.  It is amazing how a line or two of actual example code really does make a difference.  From your original post and follow up, it was impossible to ascertain where one should clear the global flag.  Nor have you ever shown how one would set the item to a selected state.

I agree that the scenario I painted is unlikely (even impossible) to occur,  assuming that MFC and Comctl32.dll never change their *undocumented*  behaviors of using SendMessage and triggering LVN_ITEMCHANGED immediately before return from the LVM_SETITEMSTATE SendMessage call.  

Regarding your position vis-a-vis the use of undocumented flags: You are entirely correct.  But if Microsoft changes the usage of bit flags (without introducing, say ComCtrls32a.DLL), lots of program would need to be upgraded (commerical program are upgraded constantly in any case).  I still maintain that keeping the information with the object is the elegant way to solve the problem as stated.

-- dan


 

0
 
LVL 1

Expert Comment

by:MT_MU
ID: 2807504
Ewq - didn't ask how to set the item selected state - I assumed it was a fair assumption that he "knew" how to do that.

Re - my flag being global - not global in the sense of program wide global, but only within the class.

I normally include the flag - and the function set the selected state as members of the class I'm working with.

Regarding Microsoft changing the usage of the bit flags - it would only be a problem for programmers using the undocumented bits. The could obviously extend the functionality but "defining" a usage for the unused bits - without breaking code.
0
 

Author Comment

by:ewajoz
ID: 2808688

MT_MU, you were right, I used the flag exactly as you thought. Using PostMessage even did not come to my mind, it would be unwise. My application has just one thread. I just understood Dan's objection that the user might select an item between setting the flag on and calling OnItemChange handler, but just realised that it is not only very unlikely, but even impossible.

MT_MU, Dan
It looks like we can finish the discussion. Thank you for pointing out how complex even the simplest question can be and for your help. It was a good lesson for me.
Best regards,
Ewa.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now