15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


CListCtrl : Fastest Method To Get Selected Items ?

Raja Segar -- rsz@pc.jaring.my
Friday, January 03, 1997

Environment: Win95, NT 3.51, Visual C++ 4.2b Patched 


Hi there,
      
    Here is the situation.
    Finding the current selected item in the CListCtrl or all the
    selected items is unbearingly slow if the number of items in
    a ListCtrl in report mode is > 3000 ++.
    BTW i hardcoded the CListCtrl to be in Report Mode only.
   
    I have a Pentium 133 with 32Mb Ram. That's a pretty fast machine.

    At first i taught it would be as easy as listbox but was i wrong.
    All the info i could find was to use the method below.

    ...
    ...
    int y = 0;
    int start = -1 ; 
    while ( (y = this->GetNextItem (start++, LVNI_SELECTED )) >=0 )
    {
      pItem->iItem = y;
      ...
      ...
    }

    Too damn slow for my liking especially if the selected item are
    at the very bottom.

    So i figured it would be much faster to keep a list of all the selected
    items as they are clicked or selected. Good Idea .
 
    But then i find out the hard way the OnClick method does not return the
    current item. 
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    CurItem =  pNMListView.iItem;
    The only bad news is that CurItem is always 655320 :(

    Then  i taught i could use the item changing messages.
    LVN_ITEMCHANGED & LVN_ITEMCHANGING.

    Man they worked .. i taught all my problems were over but
    for some weird reason each of the method is getting fired 3 or 4
    times for a simple click? 

    Err .. handling this situation would be tricky. Plus i would have
    to handle all the clicks with the ctrl key or shift key held down 
    ...wooooohhh this would be very complicated. 

    So i taught  i should consult the experts before doing this. 
    So here i am ...
   
    Anyone with any info on this matter please help out.
    Thanks in advance.
    Bye .. Happy Holidays.
     



     

    
 (  _ \/ __)(_   )
  )   /\__ \ / /_ 
 (_)\_)(___/(____)@pc.jaring.my




Dean Wiles -- deanw@isc-br.isc-br.com
Friday, January 03, 1997

> From: Raja Segar 
> To: mfc-l@netcom.com
> Subject: CListCtrl : Fastest Method To Get Selected Items ?
> Date: Friday, January 03, 1997 5:35 AM
> 
> Environment: Win95, NT 3.51, Visual C++ 4.2b Patched 
> 
> 
> Hi there,
>       
>     Here is the situation.
>     Finding the current selected item in the CListCtrl or all the
>     selected items is unbearingly slow if the number of items in
>     a ListCtrl in report mode is > 3000 ++.
>     BTW i hardcoded the CListCtrl to be in Report Mode only.
>    
>     I have a Pentium 133 with 32Mb Ram. That's a pretty fast machine.
> 
>     At first i taught it would be as easy as listbox but was i wrong.
>     All the info i could find was to use the method below.
> 
>     ...
>     ...
>     int y = 0;
>     int start = -1 ; 
>     while ( (y = this->GetNextItem (start++, LVNI_SELECTED )) >=0 )
>     {
>       pItem->iItem = y;
>       ...
>       ...
>     }
> 
>     Too damn slow for my liking especially if the selected item are
>     at the very bottom.
> 
>     So i figured it would be much faster to keep a list of all the
selected
>     items as they are clicked or selected. Good Idea .
>  
>     But then i find out the hard way the OnClick method does not return
the
>     current item. 
>     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
>     CurItem =  pNMListView.iItem;
>     The only bad news is that CurItem is always 655320 :(
> 
>     Then  i taught i could use the item changing messages.
>     LVN_ITEMCHANGED & LVN_ITEMCHANGING.
> 
>     Man they worked .. i taught all my problems were over but
>     for some weird reason each of the method is getting fired 3 or 4
>     times for a simple click? 
> 
>     Err .. handling this situation would be tricky. Plus i would have
>     to handle all the clicks with the ctrl key or shift key held down 
>     ...wooooohhh this would be very complicated. 
> 
>     So i taught  i should consult the experts before doing this. 
>     So here i am ...
>    
>     Anyone with any info on this matter please help out.
>     Thanks in advance.
>     Bye .. Happy Holidays.
>      
> 
> 
> 
>      
> 
>     
>  (  _ \/ __)(_   )
>   )   /\__ \ / /_ 
>  (_)\_)(___/(____)@pc.jaring.my
> 

I ran into a similar situation, and went a similar course.  I kept my own
list of 
elements in a CStringArray and then save the current selection in
LVN_ITEMCHANGED 
and use that for NM_CLICK and NM_RETURN:

class CMyView : public CFormView
{
    ...
    CStringArray    m_astrItem;
    int             m_iSelectedItem;
    LPARAM          m_lSelectedID;
    ...
};

...

BEGIN_MESSAGE_MAP(CMyView, CFormView)
    //{{AFX_MSG_MAP(CMyView)
    ON_NOTIFY(LVN_GETDISPINFO, IDC_MY_LIST, OnGetdispinfoMyList)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_MY_LIST, OnItemChangedMyList)
    ON_NOTIFY(NM_CLICK, IDC_MY_LIST, OnClickMyList)
    ON_NOTIFY(NM_RETURN, IDC_MY_LIST, OnReturnMyList)
    //}}AFX_MSG_MAP
    ...
END_MESSAGE_MAP()

...

void CMyView::OnGetdispinfoMyList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
    LV_ITEM* pItem = &pDispInfo->item;
    // See if we need to provide text for item
    if (pItem->mask & LVIF_TEXT)
    {
        ASSERT(pItem->pszText != NULL && pItem->cchTextMax > 0);
        // Display text for item/subitem from array
        // My CStringArray is used internally as a 2-D array that is
TABLE_WIDTH wide
        _tcsncpy(pItem->pszText, m_astrItem[pItem->iItem * TABLE_WIDTH +
pItem->iSubItem], 
            pItem->cchTextMax);
        pItem->pszText[pItem->cchTextMax - 1] = '\0';   // In case str
truncated
    }
    
    *pResult = 0;
}

void CMyView::OnItemChangedMyList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    if ((pNMListView->uChanged & LVIF_STATE) &&
        (pNMListView->uNewState & LVIS_SELECTED) &&
        !(pNMListView->uOldState & LVIS_SELECTED))  // If item was just
selected
    {
        m_iSelectedItem = pNMListView->iItem;       // Save selected item
and ID
        m_lSelectedID = pNMListView->lParam;
    }
    *pResult = 0;
}

void CMyView::OnClickMyList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    if (m_iSelectedItem != -1)          // User clicked item
    {
        DoSomething(m_iSelectedItem, m_lSelectedID);    // Display selected
item
    }
    *pResult = 0;
}

void CMyView::OnReturnMyList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    if (m_iSelectedItem != -1)         // User pressed enter on item
    {
        DoSomething(m_iSelectedItem, m_lSelectedID);    // Display selected
item
    }
    *pResult = 0;
}

void CMyView::DoSomething(int iItem, LPARAM lID)
{
    // Display selected item
    ...
}

Hope this helps.  Dean.

--------------------------------------------------------------------------
Dean Wiles (deanw@mail.isc-br.com)          Olivetti North America
Phone:  (509)927-7037                       22425 East Appleway Ave
Fax:    (509)927-2499                       Liberty Lake, WA 99019-9534
If the Son sets you free, you will be free indeed.  (John 8:36)




Kenneth A. Argo -- argo@rias.COM
Friday, January 03, 1997

[Mini-digest: 2 responses]

I did it exactly the way you found.

You should make a note that there is a flag (uNewState) that you should =
query to see what is happening to the item.

Below is a snipit from my code which has appeared to function properly =
without any problems.

My case differs from you in that I do not need to keep a list, I just =
need to keep the selected item around so I don't have to find the =
selected item later.

		if (pNMListView->uNewState & LVIS_SELECTED)
		{
			TRACE0("New item selected\n");
			m_iCurrentSel =3D pNMListView->iItem;

			// If "Open" wasn't enabled before, enable it now
			GetParent()->GetDlgItem(IDOK)->EnableWindow();

			CString *pcsCaseID =3D (CString =
*)m_cListBox.GetItemData(m_iCurrentSel);

			m_cCaseNumber.SetWindowText(*pcsCaseID);
		}
		else if (m_iCurrentSel !=3D -1 && pNMListView->uOldState & =
LVIS_SELECTED)
{
}

----------
From:  Raja Segar[SMTP:rsz@pc.jaring.my]
Sent:  Friday, January 03, 1997 8:36 AM
To:  mfc-l@netcom.com
Subject:  CListCtrl : Fastest Method To Get Selected Items ?

Environment: Win95, NT 3.51, Visual C++ 4.2b Patched=20


Hi there,
     =20
    Here is the situation.
    Finding the current selected item in the CListCtrl or all the
    selected items is unbearingly slow if the number of items in
    a ListCtrl in report mode is > 3000 ++.
    BTW i hardcoded the CListCtrl to be in Report Mode only.
  =20
    I have a Pentium 133 with 32Mb Ram. That's a pretty fast machine.

    At first i taught it would be as easy as listbox but was i wrong.
    All the info i could find was to use the method below.

    ...
    ...
    int y =3D 0;
    int start =3D -1 ;=20
    while ( (y =3D this->GetNextItem (start++, LVNI_SELECTED )) >=3D0 )
    {
      pItem->iItem =3D y;
      ...
      ...
    }

    Too damn slow for my liking especially if the selected item are
    at the very bottom.

    So i figured it would be much faster to keep a list of all the =
selected
    items as they are clicked or selected. Good Idea .
=20
    But then i find out the hard way the OnClick method does not return =
the
    current item.=20
    NM_LISTVIEW* pNMListView =3D (NM_LISTVIEW*)pNMHDR;
    CurItem =3D  pNMListView.iItem;
    The only bad news is that CurItem is always 655320 :(

    Then  i taught i could use the item changing messages.
    LVN_ITEMCHANGED & LVN_ITEMCHANGING.

    Man they worked .. i taught all my problems were over but
    for some weird reason each of the method is getting fired 3 or 4
    times for a simple click?=20

    Err .. handling this situation would be tricky. Plus i would have
    to handle all the clicks with the ctrl key or shift key held down=20
    ...wooooohhh this would be very complicated.=20

    So i taught  i should consult the experts before doing this.=20
    So here i am ...
  =20
    Anyone with any info on this matter please help out.
    Thanks in advance.
    Bye .. Happy Holidays.
    =20



    =20

   =20
 (  _ \/ __)(_   )
  )   /\__ \ / /_=20
 (_)\_)(___/(____)@pc.jaring.my


-----From: "Mittal, Vineet" 


In the OnClick event use HitTest to get the index. Here is the code
void CMyList::OnClickList(NMHDR* pNMHDR, LRESULT* pResult)
{
      CPoint curPoint;
     GetCursorPos(&curPoint);
     ScreenToClient(&curPoint);
     LV_HITTESTINFO  tmp;
     tmp.pt = curPoint;
     tmp.flags =  LVHT_ONITEM;
     m_List.HitTest(&tmp);
    *pResult = 0;
}
tmp.iItem would give the index of the currently clicked item.

Hope it helps

Vineet
 ----------
From: owner-mfc-l
To: mfc-l
Subject: CListCtrl : Fastest Method To Get Selected Items ?
Date: Friday, January 03, 1997 9:35PM

Environment: Win95, NT 3.51, Visual C++ 4.2b Patched


Hi there,

    Here is the situation.
    Finding the current selected item in the CListCtrl or all the
    selected items is unbearingly slow if the number of items in
    a ListCtrl in report mode is > 3000 ++.
    BTW i hardcoded the CListCtrl to be in Report Mode only.

    I have a Pentium 133 with 32Mb Ram. That's a pretty fast machine.

    At first i taught it would be as easy as listbox but was i wrong.
    All the info i could find was to use the method below.

    ...
    ...
    int y = 0;
    int start = -1 ;
    while ( (y = this->GetNextItem (start++, LVNI_SELECTED )) >=0 )
    {
      pItem->iItem = y;
      ...
      ...
    }

    Too damn slow for my liking especially if the selected item are
    at the very bottom.

    So i figured it would be much faster to keep a list of all the selected
    items as they are clicked or selected. Good Idea .

    But then i find out the hard way the OnClick method does not return the
    current item.
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    CurItem =  pNMListView.iItem;
    The only bad news is that CurItem is always 655320 :(

    Then  i taught i could use the item changing messages.
    LVN_ITEMCHANGED & LVN_ITEMCHANGING.

    Man they worked .. i taught all my problems were over but
    for some weird reason each of the method is getting fired 3 or 4
    times for a simple click?

    Err .. handling this situation would be tricky. Plus i would have
    to handle all the clicks with the ctrl key or shift key held down
    ...wooooohhh this would be very complicated.

    So i taught  i should consult the experts before doing this.
    So here i am ...

    Anyone with any info on this matter please help out.
    Thanks in advance.
    Bye .. Happy Holidays.







 (  _ \/ __)(_   )
  )   /\__ \ / /_
 (_)\_)(___/(____)@pc.jaring.my




Greg Lose -- glose@ArkansasUSA.com
Friday, January 03, 1997

Raja -

My list is cathcing the OnChange message and seems to be working great.
Below is the code I'm using 


	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	CString theBuffer;

	if((pNMListView->uNewState & LVIS_SELECTED) != 0 )
	{
		LV_ITEM ListItem;
		ListItem.mask = LVIF_TEXT;
		ListItem.iItem = pNMListView->iItem; 
		ListItem.iSubItem = 0;
		ListItem.pszText = theBuffer.GetBuffer(50);
		ListItem.cchTextMax = 50;

		m_MyList->GetItem(&ListItem);

		theBuffer.ReleaseBuffer();

		m_CurrSelected = theBuffer;
		
		m_SelectedItem = pNMListView->iItem;

		FireSelectionChanged();
	}
	
	*pResult = 0;


Hope this helps

Greg Lose
DOCS, Inc.
----------
> From: Raja Segar 
> To: mfc-l@netcom.com
> Subject: CListCtrl : Fastest Method To Get Selected Items ?
> Date: Friday, January 03, 1997 7:35 AM
> 
> Environment: Win95, NT 3.51, Visual C++ 4.2b Patched 
> 
> 
> Hi there,
>       
>     Here is the situation.
>     Finding the current selected item in the CListCtrl or all the
>     selected items is unbearingly slow if the number of items in
>     a ListCtrl in report mode is > 3000 ++.
>     BTW i hardcoded the CListCtrl to be in Report Mode only.
>    
>     I have a Pentium 133 with 32Mb Ram. That's a pretty fast machine.
> 
>     At first i taught it would be as easy as listbox but was i wrong.
>     All the info i could find was to use the method below.
> 
>     ...
>     ...
>     int y = 0;
>     int start = -1 ; 
>     while ( (y = this->GetNextItem (start++, LVNI_SELECTED )) >=0 )
>     {
>       pItem->iItem = y;
>       ...
>       ...
>     }
> 
>     Too damn slow for my liking especially if the selected item are
>     at the very bottom.
> 
>     So i figured it would be much faster to keep a list of all the
selected
>     items as they are clicked or selected. Good Idea .
>  
>     But then i find out the hard way the OnClick method does not return
the
>     current item. 
>     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
>     CurItem =  pNMListView.iItem;
>     The only bad news is that CurItem is always 655320 :(
> 
>     Then  i taught i could use the item changing messages.
>     LVN_ITEMCHANGED & LVN_ITEMCHANGING.
> 
>     Man they worked .. i taught all my problems were over but
>     for some weird reason each of the method is getting fired 3 or 4
>     times for a simple click? 
> 
>     Err .. handling this situation would be tricky. Plus i would have
>     to handle all the clicks with the ctrl key or shift key held down 
>     ...wooooohhh this would be very complicated. 
> 
>     So i taught  i should consult the experts before doing this. 
>     So here i am ...
>    
>     Anyone with any info on this matter please help out.
>     Thanks in advance.
>     Bye .. Happy Holidays.
>      
> 
> 
> 
>      
> 
>     
>  (  _ \/ __)(_   )
>   )   /\__ \ / /_ 
>  (_)\_)(___/(____)@pc.jaring.my



Mike Blaszczak -- mikeblas@nwlink.com
Saturday, January 04, 1997

At 21:35 1/3/97 +0800, Raja Segar wrote:
>Environment: Win95, NT 3.51, Visual C++ 4.2b Patched 

>    All the info i could find was to use the method below.

>    int y = 0;
>    int start = -1 ; 
>    while ( (y = this->GetNextItem (start++, LVNI_SELECTED )) >=0 )
>    {
>      pItem->iItem = y;
>      ...
>      ...
>    }

This is very wrong: you're doing far more work than you need to. 
Unless your loop changes the selected item, you should continue
searching by using the last item you found, not by using an
incremented count. Like this:

int y = -1;
while ( (y = this->GetNextItem (y, LVNI_SELECTED )) >=0 )
{
  pItem->iItem = y;
  // do work with it ...
}

It's hard to fathom how your code would work, anyway--it seems like your
loop would repeatedly process selected items since the way you're
searching for them ends up finding the same item again and again. If
you're doing something expensive with each iteration of the loop,
that would certainly account for your code's poor performance!  If you
have three thousand items and the 2700th item is selected, not only will
you call GetNextItem() 3000 times, you'll process the 2700th item 2700
times!

My modified loop would only call GetNextItem() twice, and only process
the 2700th item a single time.

It seems like you could have noticed this problem in your code
by tracing through it yourself just once.

.B ekiM
http://www.nwlink.com/~mikeblas/
I'm afraid I've become some sort of speed freak.
These words are my own. I do not speak on behalf of Microsoft.




Mario Contestabile -- Mario_Contestabile.UOS__MTL@UOSMTL2.universal.com
Monday, January 06, 1997

 const INT nSelected = m_ListCtrl.GetSelectedCount();
 if( nSelected > 1){ // multiple selection
  CMapIntToString mapSelection;
  INT state = -1; // start from top 
  for(INT done = 0; done < nSelected; done++){
   if( (state = m_ListCtrl.GetNextItem(state, LVNI_SELECTED)) != -1){    
    mapSelection[done] = m_ListCtrl.GetItemText(state, 0);
    TRACE1("%s is selected\n", m_ListCtrl.GetItemText(state, 0) );
   }else{
    break;
   }
  }
 }

mcontest@universal.com

====== Snip =========
    int y =3D 0;
    int start =3D -1 ;=20
    while ( (y =3D this->GetNextItem (start++, LVNI_SELECTED )) >=3D0 )
    {
      pItem->iItem =3D y;
      ...
      ...
    }

    Too damn slow for my liking especially if the selected item are
    at the very bottom.





| Вернуться в корень Архива |