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

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


Using CListCtrl as a mulicolumn listbox problem width delete

Leif Terje Fonnes -- fonlei-b.pcb@gmail.gar.no
Tuesday, February 20, 1996

Env : Visual C++ 4.0 / NTS 3.51

I am trying to use CListCntrl as a mulicolumn listbox.
It is quite easy to build up the columns, but when it comes to
finding the selected items its difficult.
I have tried varius combination of the following :

m_tlvAttr mapped against ac CListCtrl in a dialogbox width report view.

for(int i=m_tlvAttr.GetItemCount()-1;i>=0;i--)
{
  LV_ITEM lv;
  lv.mask = LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
  lv.iItem = i;
  lv.iSubItem = 0;
  if(m_tlvAttr.GetItem( &lv))
  {
    if((lv.state & LVIS_SELECTED))
    {
      // Control never comes here
      CString strText;
      strText.Format("Item %d selected",i);
      AfxMessageBox(strText);
    }
  }
}

When you look at the documentation you can get the impression that this should work.


Leif Terje Fonnes
ProgramArkitekten AS
Norway




Matt Gradwohl -- Matt_Gradwohl@msn.com
Wednesday, February 21, 1996

[Mini-digest: 5 responses]

Try something like this...

	int iItem;
	CObject* pObejct;

	CListCtrl& theListCtrl=GetListCtrl();
	iNextFocus=iItem=theListCtrl.GetNextItem( -1, LVNI_SELECTED);
	while (iItem != -1)
	{
		pObject= (CObject*) theListCtrl.GetItemData(iItem);
		ASSERT (pObject);
		// Do something with object, like pObject->Method();
		// Or pDoc->DeleteItem( pObject );
		iItem=theListCtrl.GetNextItem( -1, LVNI_SELECTED);
	}

-Matt
-----From: Peter Andersson 

To get a selected item in a CListCtrl:

GetNextItem(-1,LVNI_SELECTED);

(Finds the first selected item in the control.
The first argument is the starting index. -1 starts at the beginning.)

Look at the documentation for GetNextItem.

Hope this helps......
/Peter

-----From: Alok Khanna 

What you are missing is setting the stateMask. Set it to
LVIS_SELECTED and it will work. Please look at the
documentation of LVM_GETITEM and you will understand what I am saying. Hope
this helps. Another way of going the same things is:

if (LVIS_SELECTED == m_tlvAttr.GetItemState(i, LVIS_SELECTED)) {
.......
}

>  lv.iItem = i;
>  lv.iSubItem = 0;
>  if(m_tlvAttr.GetItem( &lv))
>  {
>    if((lv.state & LVIS_SELECTED))
>    {
>      // Control never comes here
>      CString strText;
>      strText.Format("Item %d selected",i);
>      AfxMessageBox(strText);
>    }
>  }
>}
>
>When you look at the documentation you can get the impression that this should work.
>
>
>Leif Terje Fonnes
>ProgramArkitekten AS
>Norway
>

Let me know if this works. 

Alok Khanna
CLARITECH Corporation.
-----From: Klaus Kurzawa 


Hi Leif,

You can't do it Your way because let say that You have 5 items and item 3 and 4 
are selected You never get the selected items.


Here is how You should do:

int iSelected = -1;
while ((iSelected=m_tlvAttr.GetNextItem(iSelected, LVNI_SELECTED)) != -1)
{
        // Control should come here
        CString strText;
        strText.Format("Item %d selected",iSelected); 
        AfxMessageBox(strText);
}

/Klaus Kurzawa
 klausk@cadpoint.se

-----From: Mario Contestabile 

[Snip()]
I am trying to use CListCntrl as a mulicolumn listbox.
It is quite easy to build up the columns, but when it comes to
finding the selected items its difficult.
I have tried varius combination of the following :

m_tlvAttr mapped against ac CListCtrl in a dialogbox width report view.

for(int i=m_tlvAttr.GetItemCount()-1;i>=0;i--)
{
  LV_ITEM lv;
  lv.mask = LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
  lv.iItem = i;
  lv.iSubItem = 0;
  if(m_tlvAttr.GetItem( &lv))
  {
    if((lv.state & LVIS_SELECTED))
    {
      // Control never comes here
      CString strText;
      strText.Format("Item %d selected",i);
      AfxMessageBox(strText);
    }
  }
}
[End->Snip()]

Assuming you allow multiple selection (thus the LVS_SINGLESEL was not used) in 
the
control, you can obtain all the selected items like this:

void yourlistview::OnRButtonDown(UINT nFlags, CPoint point) 
{
 CListView::OnRButtonDown(nFlags, point);

 LV_HITTESTINFO lvh;
 lvh.pt = point;

 if(m_ListCtrl.HitTest(&lvh) == -1) return; // m_ListCtrl is a class member of 
type CLIstCtrl& initialized in CTOR with GetListCtrl()

 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;
   }
  }
 }

The mapSelection CMap would contain the text of the selected items.

mcontest@universal.com




Josef Haslinger -- hasling@art.at
Wednesday, February 21, 1996

[Mini-digest: 5 responses]

>I am trying to use CListCntrl as a mulicolumn listbox.
>It is quite easy to build up the columns, but when it comes to
>finding the selected items its difficult.
>I have tried varius combination of the following :

>m_tlvAttr mapped against ac CListCtrl in a dialogbox width report view.

>for(int i=3Dm_tlvAttr.GetItemCount()-1;i>=3D0;i--)
>{
>  LV_ITEM lv;
>  lv.mask =3D LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
>  lv.iItem =3D i;
>  lv.iSubItem =3D 0;
>  if(m_tlvAttr.GetItem( &lv))
>  {
>    if((lv.state & LVIS_SELECTED))
>    {
>      // Control never comes here
>      CString strText;
>      strText.Format("Item %d selected",i);
>      AfxMessageBox(strText);
>    }
>  }
>}

>When you look at the documentation you can get the impression that this =
>should work.

I agree with you, that the documentation for the common controls is not =
"very good". IMHO you have to try a lot, to find out how these controls =
really work. If someone ever finds out all the secrects of list/tree =
views
please write them down (and post'em to me!)

In your example you have to specifiy the address and the length of the =
buffer where the found items text will be stored in lv.pszText and =
lv.cchTextMax.

It is good practice to do a=20
memset( &lv, sizeof( lv )); =20
before setting the fields of the struct.


BTW: If you just want to find the current selected item(s) use

  int nCurSel =3D  m_tlv.GetNextItem( -1, LVNI_SELECTED );
or=20
  int nCurSel =3D  m_tlv.GetNextItem( nStartFromHere, LVNI_SELECTED );

I hope this helps.

hasling@art.at (Josef Haslinger)

-----From: "Mike Blaszczak" 

From: 	owner-mfc-l@netcom.com on behalf of Leif Terje Fonnes
Sent: 	Tuesday, February 20, 1996 07:29


> Env : Visual C++ 4.0 / NTS 3.51

Thanks.

 > When you look at the documentation you can get the impression that this 
should work.

I don't think you would--the documentation says that you need to set stateMask 
if you want to play with state. I think your code isn't working because you're 
not setting stateMask.

It's also far more efficient to use CListCtrl::GeNextItem(LVNI_SELECTED) to 
find selected items.

.B ekiM
const TCHAR sz[] = _T("Out on the porch 'cause I lost my house key.");

-----From: Maurice Jeter 

I use this piece of code to iterate one of my listview controls:

selindex=m_list.GetNextItem(-1,LVNI_SELECTED); /* Finds first selected item */
while(selindex>=0) {
   ..do something..
   selindex=m_list.GetNextItem(selindex,LVNI_BELOW|LVNI_SELECTED); /* Finds
the rest */
   }

It just finds all selected items in m_list and assigns the index to selindex.

Maurice
http://www.vnet.net/users/mauricej

-----From: Leif Terje Fonnes 

Thanks for the help. I works. Btw. you are quite right that I had
forgotten to assign lv.pszText and lv.cchTextMax. It made my program crash
at the end of the procedure and it where quite difficult to spot the
error. So using my original code the solutions can be someting like this

char szBuffer[100]
for(int i=m_tlvAttr.GetItemCount()-1;i>=0;i--)
{
  LV_ITEM lv;
  lv.mask = LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
  lv.iItem = i;
  lv.iSubItem = 0;

  // New lines
  lv.statemask = LVIS_SELECTED;
  lv.pszText = szBuffer;
  lv.cchMaxText = 100;
  // New lines end

  if(m_tlvAttr.GetItem( &lv))
  {
    if((lv.state & LVIS_SELECTED))
    {
      // Control never comes here
      CString strText;
      strText.Format("Item %d selected",i);
      AfxMessageBox(strText);
    }
  }
}

But your example using
int nCurSel =  m_tlv.GetNextItem( nStartFromHere, LVNI_SELECTED );
are probaly somewhat faster.



Leif Terje Fonnes
ProgramArkitekten As
Norway
-----From: Lee Thompson 

Use GetNextItem to get each item with a specified state.

	CListCtrl	m_ListCtrl;

	int current_index = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
	if(current_index == -1)
		return;


Lee Thompson,
Lee Software

Modified Stolen Disclaimer:
--
TCHAR szDisc[] = _T("These words are my own; I do not speak, I type!");



Mike Blaszczak -- mikeblas@msn.com
Saturday, February 24, 1996

----------
From: 	owner-mfc-l@netcom.com on behalf of Josef Haslinger
Sent: 	Friday, February 23, 1996 01:03

> I agree with you, that the documentation for the common controls is not
> "very good". IMHO you have to try a lot, to find out how these controls
> really work. If someone ever finds out all the secrects of list/tree
> views please write them down (and post'em to me!)

There are many books you can buy which cover the details of the controls; I 
wrote one of them. You can also go to the MSDN library and read the MSJ 
article series on the common controls.

I disagree with you: there is plenty of documentation on the controls. 
stateMask is well-documented. Pulling stunts with controls is something you 
have to read about elsewhere or learn on your own, just like WinWord describes 
how to format paragraphs without teaching you whatever language you're using.

If you don't like the MFC documentation on the classes, you can always check 
with the SDK documentation. It's generally very complete and quite clear. It 
also has the advantage of being updated more often than the MFC documentation. 
Translating from the documentation on the underlying controls to the 
interfaces supplied by the classes is pretty trivial, I think.

If you stumble on those errors, by the way, you should write to 
vcdocs@microsoft.com to make sure the documentation team can get them fixed. I 
think that, outside of MSDN itself, the VC++ documentaiton is the largest doc 
set that Microsoft ships.

> In your example you have to specifiy the address and the length of the =
> buffer where the found items text will be stored in lv.pszText and =
> lv.cchTextMax.

Yep, since LVIF_TEXT is specified in the flags, the original poster should 
have done this, too. That's also a well-documented fact.

.B ekiM
#ifdef _IMPOSTER
TCHAR szDisc[] = _T("These words are my own; I do not speak, I type!");
#else
TCHAR szError[] = _T("Not yet implemented: try again later.");
#endif






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