Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CListCtrl, hide and edit

206 views
Skip to first unread message

Bill Brehm

unread,
May 4, 2008, 10:37:59 AM5/4/08
to
MFC 6.0. The Help implied that I can hide an item in a CListCtrl. But I
can't find out how to do it. I'd like to be able to fill a CListCtrl with a
set of data, then filter to show only a subset by hiding all those items not
in the subset.

Also, GetEditControl() implies (to me at least) that I can get a CEdit
pointer edit an item (or subitem?) in a CListCtrl. But I can't see how to
specify the item or subitem to be edited. I have a different CListCtrl with
a number of items that I would like to edit in place to allow the user to
configure something.

Thanks for any suggestions.

Bill


Bill Brehm

unread,
May 4, 2008, 11:10:08 AM5/4/08
to
When an item is hidden it should make the row height to zero, not just blank
out the row. In fact, if it were possible to set the row height to zero that
would serve my purpose. I could already blank the row by returning "" in the
callback but that wouldn't look nice or suit my purpose.

"Bill Brehm" <don't want spam> wrote in message
news:OFHl1Rfr...@TK2MSFTNGP04.phx.gbl...

David Webber

unread,
May 4, 2008, 1:04:23 PM5/4/08
to

"Bill Brehm" <don't want spam> wrote in message
news:OFHl1Rfr...@TK2MSFTNGP04.phx.gbl...

> MFC 6.0. The Help implied that I can hide an item in a CListCtrl. But I

In circumstances like this I

- derive my own class from CListBox
- store in it a collection of ALL objects which can be selected (usually in
a vector)
- add to the list box only those which need to be seen.
- in particular I put the text I want to show in the list item, and store a
pointer to the corresponding object as the list item's data.

When the set of objects I want to show changes, I

- empty everything out of the list,
- add the new set of objects I want to show in the same way.

HTH

Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mozartists/mailinglist.htm


Bill Brehm

unread,
May 4, 2008, 7:28:29 PM5/4/08
to
Dave,

Your idea was my plan B. Problem is I have a lot of items in my list so
deleting everything out and re-adding everything takes quite some time.
That's why I was looking for a plan A. Are you saying I guess that there is
no way to hide items or size a row?

Is there a way to edit in place?

Thanks,

Bill


"David Webber" <da...@musical-dot-demon-dot-co.uk> wrote in message
news:eJ9gLqgr...@TK2MSFTNGP02.phx.gbl...

Joseph M. Newcomer

unread,
May 5, 2008, 2:29:34 AM5/5/08
to
You can't show/hide elements of a CListBox or CListCtrl. Note that making the size 0 will
just confuse the user who might be using arrow keys to move up and down.

Look into virtual listboxes or virtual list controls. You don't need to keep re-adding
everything
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Bill Brehm

unread,
May 5, 2008, 1:05:01 PM5/5/08
to
Joe,

Good point about the zero sized row.

I already provide all the data to the list control via the callback
OnGetdispinfoList(). I set the Owner Data attribute without changing
anything else. Apparently the lParam is no longer stored in the item so my
program displays the first item in each location. I can use the iItem number
instead to solve that and it looks correct. Sorting gives an ASSERT now but
that depends on lParam too so it's not surprising. However, how do I solve
that because I can't get at the iItem number in the compare function.

Also, how do I deal with the number of items in the list control? I could
imagine I just set the size of the list to the total number of items I
should be displaying. It should be fast to do that - the control just
allocates or deallocates memory. Is that correct?

Lastly, is it possible to edit a list control subitem in place? If not, what
is the purpose of EditLabel()? Oh wait. I set Edit Labels. Now I can get an
in place edit of the first column. How can I do the other columns?

Thanks,

Bill


"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:g8at14dqekitbjphp...@4ax.com...

Joseph M. Newcomer

unread,
May 5, 2008, 2:54:24 PM5/5/08
to
See below..

On Tue, 6 May 2008 01:05:01 +0800, "Bill Brehm" <don't want spam> wrote:

>Joe,
>
>Good point about the zero sized row.
>
>I already provide all the data to the list control via the callback
>OnGetdispinfoList(). I set the Owner Data attribute without changing
>anything else. Apparently the lParam is no longer stored in the item

****
In a virtual control, indeed, there is no data storage at all.
****


>program displays the first item in each location. I can use the iItem number
>instead to solve that and it looks correct. Sorting gives an ASSERT now but
>that depends on lParam too so it's not surprising. However, how do I solve
>that because I can't get at the iItem number in the compare function.

****
Tom Serface is our virtual-CListCtrl guru, perhaps he can answer this. I've not used
virtual controls because I typically have a small number of items to store, and there are
only a few cases where I *should* have used one, but because it was not a "product
deliverable" but a personal hobby project, I didn't bother.
****


>
>Also, how do I deal with the number of items in the list control? I could
>imagine I just set the size of the list to the total number of items I
>should be displaying. It should be fast to do that - the control just
>allocates or deallocates memory. Is that correct?

****
For a virtual control, there is no allocation at all, which is why you get the
performance.
***


>
>Lastly, is it possible to edit a list control subitem in place? If not, what
>is the purpose of EditLabel()? Oh wait. I set Edit Labels. Now I can get an
>in place edit of the first column. How can I do the other columns?

****
Due to fundamental failures of design, a CListCtrl only allows the editing of the 0th
elment, making it nearly useless for anything that has sophisiticated constraints (for
example, I'd like the 0th element to be the index, but now I have to get into manipulating
the column order to make the one-and-only-editable-field be the logical column 0 while
displaying some other column in the leftmost position, a real pain). I think there are
some articles in www.codeproject.com on creating a CListCtrl subclass in which any column
can be edited, and I would consider looking there first.
joe
****

Tom Serface

unread,
May 5, 2008, 4:03:38 PM5/5/08
to
I typically sort the items in my memory list (the one the list control is
calling on to get it's value line by line). Of course the memory list can
be just about anything, but for me it's typically a vector of CObList of
objects so sorting is usually based off of one of the items in the object.
For example, I typically have a list of items that I just call a routine on
like:

bool CDialogWithList::CompareAndSwapString1(int pos, bool bAscending)
{
CMyObjectInfo *temp;
int posFirst = pos;
int posNext = pos + 1;

if(!bAscending) {
if (((CMyObjectInfo *)GetAt(posFirst))->m_csString1 <
((CMyObjectInfo *)GetAt(posNext))->m_csString1) {
temp = (CMyObjectInfo *)GetAt(posFirst);
SetAt(posFirst, GetAt(posNext));
SetAt(posNext, temp);
return TRUE;
}
}
else if (((CMyObjectInfo *)GetAt(posFirst))->m_csString1 >
((CMyObjectInfo *)GetAt(posNext))->m_csString1) {
temp = (CMyObjectInfo *)GetAt(posFirst);
SetAt(posFirst, GetAt(posNext));
SetAt(posNext, temp);
return TRUE;
}
return FALSE;
}

bool CDataFileArray::CompareAndSwapDate(int pos, bool bAscending)
{
CMyObjectInfo *temp;
int posFirst = pos;
int posNext = pos + 1;
if(!bAscending) {
if (((CMyObjectInfo *)GetAt(posFirst))->m_cDate <
((CMyObjectInfo *)GetAt(posNext))->m_cDate) {
temp = (CMyObjectInfo *)GetAt(posFirst);
SetAt(posFirst, GetAt(posNext));
SetAt(posNext, temp);
return TRUE;
}
}
else if (((CMyObjectInfo *)GetAt(posFirst))->m_cDate >
((CMyObjectInfo *)GetAt(posNext))->m_cDate) {
temp = (CMyObjectInfo *)GetAt(posFirst);
SetAt(posFirst, GetAt(posNext));
SetAt(posNext, temp);
return TRUE;
}
return FALSE;
}

Then I call a routine to Sort the object list like:

void CMyDialogWithList::Sort(MY_DATA_SORT_ITEMS nSort, bool bAscending)
{
bool bNotDone = TRUE;
int pos = 0;

while (bNotDone) {
bNotDone = FALSE;
switch(nSort) {
case MY_DATA_SORT_NONE:
break;
case MY_DATA_SORT_STRING1:
for(pos = 0;pos < GetUpperBound();pos++)
bNotDone |= CompareAndSwapString1(pos, bAscending);
break;
case MY_DATA_SORT_STRING2:
for(pos = 0;pos < GetUpperBound();pos++)
bNotDone |= CompareAndSwapString2(pos, bAscending);
break;
case MY_DATA_SORT_DATE:
for(pos = 0;pos < GetUpperBound();pos++)
bNotDone |= CompareAndSwapDate(pos, bAscending);
break;
default:
break;
};
}
}

So I don't use the sort mechanism in the list control at all. When the
column wants to sort I just sort the list then refresh the current screen
and only the items on the screen are drawn. I also move it back to the top
of the list when someone sorts one of the columns. I think is sort of
expected behavior. This is may not be the most efficient method for doing
sorting, but it works well and keeps the object list in an order that I can
write out and read back in the same order as the user last sorted.

Also, you can edit sub-items, but you have create your own edit control or
trick it into think it is colums 0. For example:

http://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/article.php/c4175/

It's not that difficult once you get it implemented.

Tom

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:cllu14ti1a6i5oebn...@4ax.com...
> See below..

Bill Brehm

unread,
May 5, 2008, 8:32:50 PM5/5/08
to
Thanks Joe and Tom. I think I have all I need to proceed.

"Tom Serface" <tom.n...@camaswood.com> wrote in message
news:EE4BFD17-0635-434D...@microsoft.com...

Joseph M. Newcomer

unread,
May 5, 2008, 11:26:59 PM5/5/08
to
Looks like n**2 bubble sort. Works OK for small n, but for large n, it is a killer. I
tend to just use qsort because it is n*log(n)

I once had an app which required sorting a doubly-linked list. The problem was that old
data files were unsorted. So what I did was for any version of the file < k (the version
k was the one that now required the list be maintained in ascending order, for realtime
performance), I would run across the list once; if it was in order, I left it alone.

If it was not in order, I allocated a vector of count-of-list-elements pointers, put a
pointer to every list element in it, qsorted the array, then ran through the array,
linking up the elements in sorted order. This whole operation took under 5 seconds on an
80286 (read: small memory). The problem was that for very large arrays, we discovered in
beta testing, when I did the malloc(n * sizeof(void *)), I got back NULL because there
wasn't enough space to allocate the side vector. In that case, I popped up a status
display saying "Updating older format file to new format, please be patient, this may take
several minutes" and proceeded to do a bubble sort, which could take up to three minutes.
Of course, once we wrote the file back out in the new format, we knew it was in order and
didn't have to go through this again.

But it really pointed out how n**2 and n*log2(n) differ in performance.
joe

Tom Serface

unread,
May 6, 2008, 1:36:28 AM5/6/08
to
Yeah, obviously you can replace the sort routine with anything that works
for your data. This is a simple way to get started and a really easy one to
implement even with weird lists of objects. You're right. If you had 200K
records it could take a few seconds, but for 100K it is not too bad on
today's machine and if everything is in memory.

Tom

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:pjjv14528scnr2kn6...@4ax.com...

Giovanni Dicanio

unread,
May 6, 2008, 5:25:44 AM5/6/08
to

"Tom Serface" <tom.n...@camaswood.com> ha scritto nel messaggio
news:EE4BFD17-0635-434D...@microsoft.com...

> bool CDialogWithList::CompareAndSwapString1(int pos, bool bAscending)
> {
> CMyObjectInfo *temp;
> int posFirst = pos;
> int posNext = pos + 1;
>
> if(!bAscending) {
> if (((CMyObjectInfo *)GetAt(posFirst))->m_csString1 <
> ((CMyObjectInfo *)GetAt(posNext))->m_csString1) {
> temp = (CMyObjectInfo *)GetAt(posFirst);
> SetAt(posFirst, GetAt(posNext));
> SetAt(posNext, temp);
> return TRUE;

[...]

Thanks for sharing your code, Tom.

Just a little note: I think there is a simple typo here:

I believe that Tom meant returning 'BOOL' type in his code (instead of
'bool'), in fact he returns 'TRUE' and 'FALSE' values.
(If the return type is 'bool', I think we should return 'true' and 'false'.)

G


Giovanni Dicanio

unread,
May 6, 2008, 5:32:00 AM5/6/08
to

"Tom Serface" <tom.n...@camaswood.com> ha scritto nel messaggio
news:AFD785C0-EB1B-467F...@microsoft.com...

> Yeah, obviously you can replace the sort routine with anything that works
> for your data.

If we store data in STL containers like std::vector, we can use the
std::sort algorithm (ready "off the shelf", is that the right expression? :)

std::sort algorithm has O(N * log(N)) sort complexity.

std::sort
http://msdn.microsoft.com/en-us/library/ecdecxh1(VS.80).aspx

However, as you wrote, I think that on modern hardware the difference is on
big amounts of data (several hundreds thousands).

G


Tom Serface

unread,
May 6, 2008, 10:03:31 AM5/6/08
to
You're right. I always get those mixed up. I was just putting in an
example. Or course, in this case it will convert it for me so it would
still work OK.

Tom

"Giovanni Dicanio" <giovanni...@invalid.com> wrote in message
news:uynLJt1...@TK2MSFTNGP05.phx.gbl...

Tom Serface

unread,
May 6, 2008, 10:06:40 AM5/6/08
to
Yeah, that would work. Fortunately we're just shuffling pointers so it's
pretty quick regardless.

"off the shelf" "out of the box" means the same thing... of course you'd
have to write some code still since you'll want to be able to sort by any
column or even multiple columns perhaps.

Tom

"Giovanni Dicanio" <giovanni...@invalid.com> wrote in message

news:Oo0otw1r...@TK2MSFTNGP02.phx.gbl...

David Connet

unread,
May 6, 2008, 10:30:06 AM5/6/08
to
"Bill Brehm" <don't want spam> wrote in
news:ueXDrItr...@TK2MSFTNGP04.phx.gbl:

> Joe,
>
> Good point about the zero sized row.
>
> I already provide all the data to the list control via the callback
> OnGetdispinfoList(). I set the Owner Data attribute without changing
> anything else. Apparently the lParam is no longer stored in the item
> so my program displays the first item in each location. I can use the
> iItem number instead to solve that and it looks correct. Sorting gives
> an ASSERT now but that depends on lParam too so it's not surprising.
> However, how do I solve that because I can't get at the iItem number
> in the compare function.
>
> Also, how do I deal with the number of items in the list control? I
> could imagine I just set the size of the list to the total number of
> items I should be displaying. It should be fast to do that - the
> control just allocates or deallocates memory. Is that correct?

In addition to what others have commented, another thing you can do is
allocate a data structure containing your data and set that as the list
item's data. Now lParam is set, and you can use the listctrl's sorting.
The key here is to handle the LVN_DELETEITEM message and delete your
data.

My data hasn't grown so large that I need a virtual list yet.

> Lastly, is it possible to edit a list control subitem in place? If
> not, what is the purpose of EditLabel()? Oh wait. I set Edit Labels.
> Now I can get an in place edit of the first column. How can I do the
> other columns?

I modified my list control to be able to do this using
http://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/arti
cle.php/c923/ as a starting point. I remember there were a couple things
I had to add that weren't handled well - like when you use the mouse
wheel to scroll (so the edit box doesn't lose focus) [in the parent
control, I set focus to that to cause the edit control to lose focus].
You can also use other controls (like a combo box).

If you want to take a look at mine, it's at
http://sourceforge.net/projects/agilitybook (specifically, the
ListCtrl.cpp file - look at the SVN code, the released source zip doesn't
have that functionality yet - I'm still working on the workflow in the
program to make use of it)

Dave Connet

Bill Brehm

unread,
May 8, 2008, 8:34:44 PM5/8/08
to
I was wondering if there is a way to display something other than text in a
subitem. Two things come to mind.

1. Could I put a checkbox in as one of the items? I would like to use it to
display a boolean value and also to allow that value to be editted.
2. Could I use one column to display the tree control type of + and - (and
maybe lines) that I could click and expand groups of items. What i'm looking
for is something like Excel's grouping capability, rather than a tree
control next to a list control, as in File Explorer. If not, what do you
think about putting a tree control next to or on top of a column of a list
control?

Thanks,

Bill

"Tom Serface" <tom.n...@camaswood.com> wrote in message
news:EE4BFD17-0635-434D...@microsoft.com...

Tom Serface

unread,
May 9, 2008, 1:07:02 AM5/9/08
to
You may just want to try something like this:

http://69.10.233.10/KB/list/xlistctrl.aspx

Even if you don't use the class you can look at the code to see how some of
the stuff is done. It was updated pretty recently.

Tom

"Bill Brehm" <don't want spam> wrote in message

news:%23euE8xW...@TK2MSFTNGP03.phx.gbl...

Joseph M. Newcomer

unread,
May 9, 2008, 11:34:40 AM5/9/08
to
Use custom-draw and you can display anything you want. I've displayed a check box,
although I was too lazy to write the code to detect the OnLButtonDown in the check box to
allow it to be changed, but that was because it was a personal project.

I've done expanding controls like list controls in CListBox, and I did it by using a
variable-height box (the limit is 255 pixels, and the nature of the data was that there
were between 1 and 5 subitems if the user wanted to see them, so we were within the 255
pixel limit). I do not know if there is a similar height restriction on CListCtrl items.

However, it sounds more like you want a custom grid control than a custom CListCtrl.
joe

Bill Brehm

unread,
May 10, 2008, 12:43:56 PM5/10/08
to
I'm working on the Owner Data part now. I notice that when I double click
the right of any column header, it no longers sizes the column to the
longest item within that column any where in the data, but only to the
longest item in the column that is currently visible. Is that normal for
Owner Data? Or did I bugger up something else? If normal, is there any way
to get the original functionality back?

I also notice that since I use qsort() to replace the built-in column sort
functionality, there is something funny going on. I looked into sorting and
it seems some implementations of qsort (this one included) are not "stable"
in that they do not preserve the order items that have identical sort keys.
Does MSVC++ 6 have a stable sort function or must I write my own?

Thanks...


"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:ajr824dack336k0v1...@4ax.com...

Joseph M. Newcomer

unread,
May 11, 2008, 12:45:44 AM5/11/08
to
This is normal for owner draw. The reason is that since you have responsibility for doing
the drawing, there is no possible way for the control to know how wide your data is, so it
cannot resize it. Therefore, you have to track the maximum size yourself, and respond to
whatever events you want to yourself.

I do not believe qsort is a stable sort; where I care about order under equality, I will,
before initiating the sort, for(all elements in list) element[i].subsort = i;
(pseudo-code). Then, when I sort, if the values are equal, I then sort on the subsort
key. This maintains original order, and makes me independent of the stable/unstable sort
issue, because, under the compare function I use, there can be no such thing as equality
of two keys. The "major keys" may be equal, but the "subsort key" is always different
because every subsort key is unique.
joe

0 new messages