Click here to Skip to main content
Click here to Skip to main content

Using virtual lists

By , 4 Aug 2004
 

Sample Image - virtuallist.gif

Contents

Introduction

Let's say you have a large database in your program and you want to show the database to the user. You use a CListCtrl with a couple of columns and fill it with a few thousand, maybe million elements. When you run it, you notice it's a bit (or very) slow. Wouldn't it be great if you didn't need to add all elements to the list, and let the list show them anyway? Does it sound stupid and ridiculous? That's how a virtual list works.

Virtual list

A virtual list is a list that has no data, it only knows how many data items it is supposed to have. But how does it now what data to show? The secret is that the list asks the parent for the information it needs. Assume you have a list with 100 elements, and elements 10-20 are visible. When the list is redrawing, it first asks the parent about element 10. When the parent has answered, the list redraws element 10, and then goes on to the next element.

A virtual list is sending three different messages to the parent. LVN_GETDISPINFO is sent when the list needs information. This is the most important message. The message LVN_ODFINDITEM is sent when the user tries to find an item by writing in the list. LVN_ODCACHEHINT is sent to give you a chance to cache data. You will probably don't care about this message at all.

OK, that's enough fuzzy theory, let's look on some code instead.

Creating a virtual list

Creating a virtual list isn't much harder than creating an ordinary CListCtrl. Add a list control in the resource editor as you usually do. Then check the style "Owner data", and then add a CListCtrl variable for this control. The only difference from an ordinary CListCtrl is the "Owner data" (LVS_OWNERDATA) style.

When you work with a virtual list, you use it mostly in the same way you do with a non-virtual list. Adding columns, selecting items, adding image list and much more works exactly the same way.

Add items to the list

Let's say m_list is the control variable for the list. Normally, you add data to the list like this:

m_list.InsertItem(0, _T("Hello world"));

But in a virtual list, this will not work. Instead, it is up to you to handle the data. Instead of adding, you change the number of elements the list is showing:

//"Add" 100 elements
m_list.SetItemCount(100);

If you set the item count to 100 or 1,000,000 doesn't matter, the time to run this command will still be practically zero. In a non-virtual list, adding a million elements could take hours.

Handling the LVN_GETDISPINFO message

As I said before, the list is asking the parent for information when it needs it. The list does this by sending a LVN_GETDISPINFO message. This is the most important message to handle when you are dealing with a virtual list. A typical function looks like this:

void CVirtualListDlg::OnGetdispinfoList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;

    //Create a pointer to the item
    LV_ITEM* pItem= &(pDispInfo)->item;

    //Which item number?
    int itemid = pItem->iItem;

    //Do the list need text information?
    if (pItem->mask & LVIF_TEXT)
    {
        CString text;

        //Which column?
        if(pItem->iSubItem == 0)
        {
            //Text is name
            text = m_database[itemid].m_name;
        }
        else if (pItem->iSubItem == 1)
        {
            //Text is slogan
            text = m_database[itemid].m_slogan;
        }

        //Copy the text to the LV_ITEM structure
        //Maximum number of characters is in pItem->cchTextMax
        lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
    }

    //Do the list need image information?
    if( pItem->mask & LVIF_IMAGE) 
    {
        //Set which image to use
        pItem->iImage=m_database[itemid].m_image;
        
        //Show check box?
        if(IsCheckBoxesVisible())
        {
            //To enable check box, we have to enable state mask...
            pItem->mask |= LVIF_STATE;
            pItem->stateMask = LVIS_STATEIMAGEMASK;

            if(m_database[itemid].m_checked)
            {
                //Turn check box on
                pItem->state = INDEXTOSTATEIMAGEMASK(2);
            }
            else
            {
                //Turn check box off
                pItem->state = INDEXTOSTATEIMAGEMASK(1);
            }
        }
    }

    *pResult = 0;
}

First, we create a LV_DISPINFO pointer, and then a pointer to the item. In itemid, we save which item we should handle. Then we check the mask in pItem. The mask is telling us what kind of information the list needs. First, we check if text information is needed. If it is, we first figure out which column the text is. The first column is for names, the second for slogans (several columns will be shown in report view, in other views only first column will be used).

We also check if image information is needed. If it is, we save which image to use in pItem->iImage (this is the number to an image in the image list connected to the list).

If check boxes are visible, we should send information about that when image information is requested. First, we change pItem->mask to tell that we are sending state information. We also change pItem->stateMask to tell what kind of information we are sending. Then we write if check box is on or off.

The mask could also have the flags LVIF_INDENT, LVIF_NORECOMPUTE, LVIF_PARAM, and LVIF_DI_SETITEM. But I have never used any of them, so I guess they aren't important :-).

It isn't harder to handle the LVN_GETDISPINFO message than this. Check boxes are probably the hardest, but you will probably never use any more complicated code than I have done in this example. When you have written this function, your list will almost act like a normal list. However, it might be a good idea to implement the LVN_ODFINDITEM as well.

Handling the LVN_ODFINDITEM message

First, some basic education: start Explorer and go to a folder where you have a lot of files. Press A. What happens? If you have a file or folder that begins with an 'A', that file should now be selected. Press A again. If you have more than one file that begins with an 'A', the second file should be selected. Write "AB". If there is any file that begins with 'AB', that is now selected. This is how every normal list control behaves. Aren't list controls cool? :-).

Let's look on how a list control normally searches:

Name
Anders
Anna
Annica
Bob
Emma
Emmanuel

Anna is selected. When we are writing anything, the list will search down to find the best match. If it reaches the end, it restarts at the top and searches until it is back on the start item (Anna). If "A" is written, Annika should be selected. If "AND" is written, Anders should be selected. If "ANNK" is written, the selection should stay on Anna. If "E" is written, Emma should be selected.

Unfortunately, this doesn't work with virtual lists. A virtual list doesn't try to find any item at all, unless you handle the LVN_ODFINDITEM message. I usually implement the message like this:

void CVirtualListDlg::OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    // pNMHDR has information about the item we should find
    // In pResult we should save which item that should be selected
    NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;

    /* pFindInfo->iStart is from which item we should search.
       We search to bottom, and then restart at top and will stop
       at pFindInfo->iStart, unless we find an item that match
     */

    // Set the default return value to -1
    // That means we didn't find any match.
    *pResult = -1;

    //Is search NOT based on string?
    if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
    {
        //This will probably never happend...
        return;
    }

    //This is the string we search for
    CString searchstr = pFindInfo->lvfi.psz;

    int startPos = pFindInfo->iStart;
    //Is startPos outside the list (happens if last item is selected)
    if(startPos >= m_list.GetItemCount())
        startPos = 0;

    int currentPos=startPos;
    
    //Let's search...
    do
    {        
        //Do this word begins with all characters in searchstr?
        if( _tcsnicmp(m_database[currentPos].m_name, 
                 searchstr, searchstr.GetLength()) == 0)
        {
            //Select this item and stop search.
            *pResult = currentPos;
            break;
        }

        //Go to next item
        currentPos++;

        //Need to restart at top?
        if(currentPos >= m_list.GetItemCount())
            currentPos = 0;

    //Stop if back to start
    }while(currentPos != startPos);        
}

It may not be obvious how this works at a first look, but if you read it carefully, you will understand. Or, you simply skip this, and copy the code and just do the necessary changes - it's up to you :-). If the list is really large, maybe you need to make a faster version of this function, or don't implement it at all.

pFindInfo->lvfi has information on how you should search (like "Restart at top if bottom is reached" or in which direction). I have never cared about that, if you do, you should read in MSDN to get more information.

Handling the LVN_ODCACHEHINT message

LVN_ODCACHEHINT is sent to give you a chance to cache data. If you are working with a database that is in another computer in some network, maybe this is useful, but I haven't used this message in any of my programs. A function that handles this message will probably look something like this:

void CVirtualListDlg::OnOdcachehintList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMLVCACHEHINT* pCacheHint = (NMLVCACHEHINT*)pNMHDR;

    // ... Cache the data pCacheHint->iFrom to pCacheHint->iTo ...

    *pResult = 0;
}

This is quite simple as you see. But as usual, simple things don't work :-). According to MSDN, you should override OnChildNotify and add the handler in this function. But I will not dig deeper in this, if you need more information about this, read in MSDN.

Changing an item

What should you do to change the data? This is really simple. You don't change the data in the list, but in the database instead. To redraw the list items, call CListCtrl::RedrawItems.

Check boxes

Check boxes are useful, but they are quite tricky to implement when you are working with a virtual list. In a normal non-virtual list, check boxes are toggled when you click on them or when you press space. But in a virtual list, nothing will happen. So you have to implement these events yourself. We start with a simple toggle-check-box-function:

void CVirtualListDlg::ToggleCheckBox(int item)
{
    //Change check box
    m_database[item].m_checked = !m_database[item].m_checked;

    //And redraw
    m_list.RedrawItems(item, item);
}

We will call this function when we want to change an item. The function toggles the check box value (in the database!) and forces the list to redraw the item. Quite simple. Toggling a check box when space is pressed is also quite simple. Add a message handler for the LVN_KEYDOWN message. The function should be something like this:

void CVirtualListDlg::OnKeydownList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;

    //If user press space, toggle flag on selected item
    if( pLVKeyDown->wVKey == VK_SPACE )
    {
        //Toggle if some item is selected
        if(m_list.GetSelectionMark() != -1)
            ToggleCheckBox( m_list.GetSelectionMark() );
    }

    *pResult = 0;
}

We check if space is pressed and if any item is selected before we toggle the check box. To toggle check box when we click on it, we have to do a more complicated function. Add a message handler for the NM_CLICK message. My function looks like this:

void CVirtualListDlg::OnClickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    LVHITTESTINFO hitinfo;
    //Copy click point
    hitinfo.pt = pNMListView->ptAction;

    //Make the hit test...
    int item = m_list.HitTest(&hitinfo); 

    if(item != -1)
    {
        //We hit one item... did we hit state image (check box)?
        //This test only works if we are in list or report mode.
        if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0)
        {
            ToggleCheckBox(item);
        }
    }
    
    *pResult = 0;
}

We are using CListCtrl::HitTest to see if we clicked on an item. If we did, the function returns which item we clicked on. We then use hitinfo.flags to see where we clicked. If the flag LVHT_ONITEMSTATEICON is on, then we know that the user clicked on the check box (state image).

Unfortunately, CListCtrl::HitTest doesn't work as it should if the list view is in "Icon" or "Small icon" mode. In these views, hitinfo.flags & LVHT_ONITEMSTATEICON is always 0. I haven't found a solution to this, if you do, let me now. However, using check boxes in these modes is probably quite unusual, so this is not a big problem.

Notes

Unless you are making something very unusual, you will not need to know more information than there is in this article, to use virtual lists. However, there are some minor compatibility issues between a virtual and a non-virtual list. For example, a virtual list can't sort data. But that is quite obvious, isn't it :-)? You find more information about these issues in MSDN.

When should you use a virtual list, and when should you not? For large lists, I personally prefer a virtual list. But a non-virtual list is usually easier to program (message handling is never fun), so for smaller lists, I use the ordinary list.

A very neat thing about virtual lists is that they are very easy to keep synchronized with a database. You just change the database and redraw the list if necessary. So, if you work with a list where the user should change data in the database, a virtual list could be useful even if number of items are low.

Another nice thing is that you sometimes could generate data when necessary. If you want to show row number in one column, that is very easy to do, and it takes practically no memory at all. In a non-virtual list, you would have to add this data on all items.

History

  • 5 August, 2004 - Initial version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

PEK
Sweden Sweden
Member
PEK is one of the millions of programmers that sometimes program so hard that he forgets how to sleep (this is especially true when he has more important things to do). He thinks that there are not enough donuts in the world. He likes when his programs works as they should do, but dislikes when his programs is more clever than he is.

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.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionhow to set the memory for itemsmemberxjsfxiongwei26 Dec '08 - 20:42 
In my project that have some long character string want to insert tha virtual list. Sometimes the string length beyond the default length( cchTextMax ).
I want to known how to point the cchTextMax for each item
QuestionHow to get current selected item?membersankking21 Apr '08 - 15:56 
If user clicks on the listctrl,how to get the seleted item exactly?
QuestionCan't croll trough my CListCtrl?membertermal17 Dec '07 - 3:23 
Hello,
i cant scroll trought my list control, i use virtual list and any time if i call
SetItemCount(list.size()); // list have all data, is type hash_map
focus jump's to top of my list, so if i just want to see what is in row 2500, focus jump to top of a
CListCtrl???
 
Any idea to solve this, how to scroll trought CListCtrl using virtual list??
 
regards
termal
QuestionHow 2 delete some items? [modified]memberElaaber10 Dec '07 - 1:17 
Hi
Thanx 4 the code.
How 2 delete some items from a virtual list control and redraw the list again?
thanx
 
A man is known by the company he keeps.
modified on Tuesday, December 11, 2007 2:25:26 AM

GeneralRe: How 2 delete some items?membertermal17 Dec '07 - 3:09 
Hello,
if not solved,i use virtual list to, and i delete them directly from the list,
and then update clistctrl from the list again!
 
If solved can you post a sample how do you do this?
 
regards
termal
GeneralSet CurrentSelectmemberLamdb15 Jul '07 - 22:10 
Hi, I am designinga dictionary so that this article is very helpful to me. I want to know how to set a position in the virtual list in the same way SetCurSelect function excuting in the non-virtual list.
Thank you.
 

GeneralCLIstCtrlmembermastp8 Jul '07 - 20:30 
hi,
How can we add bitmaps to a listcontrol
 
pernamitta
NewsSpace bar toggle check-box wrong behaviour [modified]memberWernight12 Apr '07 - 9:42 
The should toggle the checked option of the focused item, so the code before has some slighly wrong behaviour corrected here:
 
void CMyDlg::OnLvnKeydownFilenamesIn(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
 
	// If user press space, toggle flag on selected item
	if (pLVKeyDown->wVKey == VK_SPACE)
	{
/////// CHANGES START ///////
		// Toggle checked for the focused item.
		int nFocusedItem = m_ctlList.GetNextItem(-1, LVNI_FOCUSED);
		if (nFocusedItem >= 0)
			ToggleCheckBox(nFocusedItem);
/////// CHANGES END ///////
	}
 
	*pResult = 0;
}
 
I just hate all those tricky stuff everytime I want to customize a little my controls. There are just too many of them. Sniff | :^)
 
... but great article. Big Grin | :-D
 
-- modified at 9:32 Friday 13th April, 2007
 
B.A.N.Z.A.I. ! !! !!!

QuestionHow to Insert a Check Box only at 5,10memberthomas.wegele6 Nov '06 - 4:06 
Hello,
 
i have a question how is it possible to insert a sub item only at line 5 in row 10 or so.
I am Sorry, i have noting found in the article.
 

greetz.
AnswerRe: How to Insert a Check Box only at 5,10memberPEK5 Dec '06 - 8:27 
Read the article again and you will find that a virtual list doesn't handle the data, it only draws a list. It's up to you to handle the "database" which the list will use when it's draws the control.
GeneralEnsurevisible is not workingmemberRSE Thomas20 Jan '06 - 20:41 
Thank you for this excellent article.
I need to have a virtual list that whenever I add an item it is displayed at the start of the list, means reverse order. New items first and old add the end.
Or what also would be possible is to add it as it is (at the end) but always make that last entry visible at the end of the list. On a normal list you would do this with 'ensurevisible'. but this is not working on a virtual list.
Does anyone have an idea how to realize it?
Thanks a lot
Thomas
GeneralRe: Ensurevisible is not workingmemberPEK21 Jan '06 - 0:14 
EnsureVisible works with virtual lists. For example, modify OnButtonAddten with this new code:
void CVirtualListDlg::OnButtonAddten() 
{
	//Add 10 elements to the database
	for(int i=0; i<10; i++)
		m_database.push_back( CSampleData() );
 
	//Resize the list to add the elements to the list
	m_list.SetItemCount( m_database.size() );
 
	UpdateCount();
 
	m_list.EnsureVisible( m_list.GetItemCount()-1, FALSE );
}

GeneralRe: Ensurevisible is not workingmemberRSE Thomas21 Jan '06 - 7:34 
Thank you very much, it's working
i made always the stupid mistake and tried with
m_list.EnsureVisible( m_list.GetItemCount(), FALSE ); instead of
m_list.EnsureVisible( m_list.GetItemCount()-1, FALSE );
 
Thanks again
Thomas
GeneralBug with MS Tab ControlmemberSharpmike13 Jan '06 - 16:38 
Have you tried a virtual listview as a child of a tab control? I tried this in both MFC and WTL, and the same thing happens in both; the tab control doesn't seem to receive any LVN_GETDISPINFO notifications. I get all other notifications (LVN_ODCACHEHINT, NM_CUSTOMDRAW, NM_DBLCLK, etc.) The only workaround I could find is to create the control, then call SetParent on the listview to change the parent to the parent of the tab control. The parent then receives the LVN_GETDISPINFO notifications. If you have a workaround I would much appreciate it.
 
Sharpmike
GeneralRe: Bug with MS Tab ControlmemberPEK14 Jan '06 - 22:27 
Sorry, I haven't used virtual lists with tab controls. But as you said changing parent would fix this bug (I guess it is bug).

GeneralRe: Bug with MS Tab Controlmembertermal17 Apr '07 - 2:38 
Hello,
did you solve the problem with tab control?
 
regards
termal
GeneralRe: Bug with MS Tab ControlmemberSharpmike20 Apr '07 - 5:36 
Hello termal,
I haven't found what I consider a good solution...the best I can come up with is the workaround I've stated above: setting the parent of the list to the main window after creation using SetParent and handling the notifications that way. I don't see the LVN_GETDISPINFO notifications even in spy++. My guess is common controls just will not send notifications to each other, maybe because that's the primary way they communicate with parent windows. Someone else may have more insight on this.
 
Mike
Questionchange colormemberledaker12 Dec '05 - 14:12 
Hi,
how i can change color of each rows in a virtual clistctrl.
Smile | :)
AnswerRe: change colormemberPEK3 Jan '06 - 9:10 
You can't. You must either do your own custom draw control:
http://www.codeproject.com/listctrl/lvcustomdraw.asp[^]
 
or use some control that already do this for you:
http://www.codeproject.com/listctrl/quicklist.asp[^]
 


GeneralHi PEK, is it possible to use virtual list in one Class drived from CListViewmemberchaochao_cz7 Nov '05 - 21:41 
Hi PEK,
 
In my side, I am using MDI to present large data. I want to display the data in differenct views. Also I want to display the data in one view drived from CListView. Is it possible to modify its style with ModifyStyle() into LVS_OWNERDATA?
 
Do you have any suggestion on this application?
 
Thanks
 
Samuel
GeneralRe: Hi PEK, is it possible to use virtual list in one Class drived from CListViewmemberPEK8 Nov '05 - 7:43 
I haven't tested it, but it should be possible. However, using ModifyStyle() isn't enough, LVS_OWNERDATA must be set when the control is created. I think you can solve this by modifying the code when CreateWindow is called, or overriding a message.
 
This have been done before:
http://www.codeproject.com/listctrl/virtuallist.asp?msg=1275797#xx1215764xx

GeneralIt is possiblemembermadkoala2 Jan '06 - 17:28 
Surely it is possible to use virtual list in the class derived from CListView.
I have implemented it in my project.Laugh | :laugh:
 
All you need to do is to make control with LVS_OWNERDATA style included.
GeneralGreat ArticlememberGiorgi Moniava21 Oct '05 - 5:01 
But could you help me with one thing PEK ?
Could you tell me how to create manifest file , like in your application or link me to a site where it is well explained
 
Thanks in advance
 


"Success is the ability to go from one failure to another with no loss of enthusiasm." - W.Churchill


GeneralRe: Great ArticlememberPEK21 Oct '05 - 22:26 
Just copy, rename and edit my file. Or do some search at CodeProject, I'm pretty sure it's an article here about this.
QuestionHow to implement virtual list control in CListView class??memberchaochao_cz4 Sep '05 - 16:38 
If I am using CListView to display huge data,how can I implememt virtual list control ?I read some hint from MSDN that virtual list control is still applicable in CListView.
 
Any suggestion?
 
Chao Zhao
AnswerOK.I got it.I should use CreateWindow()memberchaochao_cz4 Sep '05 - 17:20 
Yeah.I should use CreateWindow() with specifying the LVS_OWNERDATA window style as part of the dwStyle function parameter.
 
Cheers!
 
Chao Zhao

NewsGreat artical to introduce virtual list control usage!memberchaochao_cz4 Sep '05 - 15:58 
Thanks for PEK's contribution on this topic!
 
This is a great artical to intruduce how to use virtual list control in one's project!In particular, it is very helpful for me.
 
CheersBig Grin | :-D
 
Chao Zhao
QuestionHow to use it to display dynamic dataset?memberLiuhan26 Aug '05 - 16:44 
I embaded a database, and have many new records every second (>100/sec), how to display it in virtual lists?( I am sorry for my pool englishSmile | :) )
 
liuhan
 

 

AnswerRe: How to use it to display dynamic dataset?memberPEK26 Aug '05 - 21:26 
It's no difference compared with the demo project in this article. Just copy the text from the database for each item when the list ask for it.
GeneralLVS_OWNERDATAmemberfasafrah23 Aug '05 - 22:40 
How to SetItemData in Owner data lists?
 
Firas
GeneralRe: LVS_OWNERDATAmemberPEK24 Aug '05 - 10:07 
It may be possible, but I don't think so. Sense you must handle all data that it used in the list, you must handle the item data too. This more or less removes the use of item data.
JokeRe: LVS_OWNERDATAmemberchaochao_cz1 Sep '05 - 15:06 
Also I am interested in this function.
 
How about using one vector<...> to instead SetItemData().Use the index of item rowid to get vector data.
 
How about it ?Confused | :confused:
 
Cheers
GeneralRe: LVS_OWNERDATAmemberCubex15 Aug '07 - 20:23 
You don't need to set item data. You have it already.
 
As you handle LVN_ODFINDITEM by accessing your data from your cache you can do so for any function by looking up the item index.
 

GeneralLVS_OWNERDATAmemberfasafrah23 Aug '05 - 22:36 
Can any one help if i can SetItemData In this Class?
pItem->mask & LVIF_PARAM is not working so far
GeneralUsing Groups with Virtual ListsmemberAndyCheetham16 Aug '05 - 2:18 
Is it possible to use groups with virtual list controls?
 
the following line never results in true!
 
if(pItem->mask & LVIF_GROUPID)
 
At present the list control works in non-virtual mode and the groups appear correctly so I know I am adding the groups to the control correctly.
 
Any ideas?
 
Cheers
AndyC
GeneralInsertItem and LPSTR_TEXTCALLBACKmemberdominicMeier22 Jun '05 - 4:58 
I have a dialog in with I have an instance if CListCtrl. Now the idea is like this: I would like to use a virtual list means somewhere in my CDialogclass I have a methode with call something like this:
 

LVITEM* NewItem = new LVITEM;
NewItem->lParam = (LPARAM) pLogItem; // Store the pointer to the data
NewItem->pszText = LPSTR_TEXTCALLBACK; // using callbacks to get the text
NewItem->mask = LVIF_IMAGE | LVIF_PARAM; // lParam and pszText fields active
NewItem->iItem = 0; // position to insert new item
NewItem->iSubItem = 0;
NewItem->iImage = pLog->Image(); // Image
 
iInsertItemOkay = m_ConLogViewTable.InsertItem(NewItem);

 
The idea is that if the text has to be display the CListCtrl send LVN_GETDISPINFO and this methode will be called
 
from messagemap:
 

ON_NOTIFY(LVN_GETDISPINFO, IDC_LOGVIEW, OnGetdispinfoLogview)

 
Inside I would do like this
 

LV_DISPINFO *pDispInfo = (LV_DISPINFO *) pNMHDR;
LV_ITEM *pItem = &(pDispInfo)->item;

if (pDispInfo->item.mask & LVIF_TEXT){
 
CLogItem *pLogItem = (CLogItem *) pItem->lParam;
 
if(pItem->lParam != 0){
pLogItem->GetListText(*pItem);
}
}

 
It works up this point where I check what is inside of the lparam where should be the pointer to my LogItem stored.
 
Questions: Why is the lParam allways NULL means Zero? I get Mad | :mad: about this soon or later
 
Thanks for any, even smalest help.
 


 
Dominic
GeneralRe: InsertItem and LPSTR_TEXTCALLBACKmemberPEK25 Jun '05 - 1:25 
That would be an elegant solution, but I'm not sure that this callback function works like this. When you get a callback message the list is expected to get information, it will not give you any information (like the value of lParam).
 
So if you need information about the item, check the iItem value and use that to get the original list item from the list. I'm not sure, but I think that will do the trick.
GeneralSomething goes wrong ...memberdhammeriz19 Mar '05 - 12:32 
1)when database recordset is larger then 30000 rows/>6 columns the non-virtual list displays the result faster then the virtual. Frown | :-( (
 
2) When I use another class derived from CListCtrl, for example the ReportCtrl class taken here from Code Project, my program crashed.
It seems there is a conflict using OnLvnGetdispinfo and ItemData.
 
Has any one the same problem ???
 
Greetings
koreson
GeneralRe: Something goes wrong ...memberPEK19 Mar '05 - 23:07 
1. I think the problem is in the recordset, not in the list view. I have run a virtual list with millions of items and haven't had any performance problems.
 
2. My guess is that ReportCtrl simply doesn't virtual mode (quite common I think).
 

GeneralRe: Something goes wrong ...sussAnonymous20 Mar '05 - 7:24 
Thank you for prompt reaktion
 
Now I get the fields from MYSql-source directly by:
mysql_data_seek (mTabelle, pItem->iItem);
mRecord = mysql_fetch_row(mTabelle);
lstrcpyn(pItem->pszText, mRecord[pItem->iSubItem], pItem->cchTextMax);
 
this is very fast. Faster then to buffer the recordsets into an vector like:
while ((mRecord = mysql_fetch_row(mTabelle)) != NULL) //Tabelle schreiben
{
m_database.push_back(vector());
 
for (int j=0; j < max_cols; j++)
{
element = mRecord[j];
m_database.back().push_back(element);
}
i++;
}
 
this vector is the reason why the display of the List is so slow.
When I get the records directly from MySQL-source it displays very fast but scrolling is very slow after the 10.000th record. Sometimes the app crash.
 
Now, I don't know which soloution I should prefer?
 
Do you have any idea. Is caching the only way?
What should I do???
The problem with the ReportCtrl class ist not so important.
 
Greetings
koreson
 
(excuse my bad English) Wink | ;)
GeneralRe: Something goes wrong ...memberPEK21 Mar '05 - 8:36 
I haven’t used recordset so I can’t say I know what I’m talking about Smile | :) . But my guess is that mysql_data_seek is pretty slow. So instead of using a recordset it may be faster to run a new SQL-query for each item. Maybe this thread is useful for you:
 
http://groups.google.se/groups?hl=sv&lr=&threadm=O%23M5cOapAHA.1924%40tkmsftngp03&rnum=6&prev=/groups%3Fq%3Dvirtual%2Blist%2Brecordset%26as_ugroup%3D*mfc*[^]

GeneralRe: Something goes wrong ...sussAnonymous23 Mar '05 - 2:42 
Hi,
 
I think too that the data_seek metod is very slow.
 
Thank you for the interessting link.
 
Greetings
koreson

GeneralRe: Something goes wrong ...sussAnonymous29 May '05 - 17:48 
I don't think list controls are able to go beyond 32,768 items... I found this somewhere in MSDN... Even when you are using virtual lists, data eventually gets allocated.
GeneralOnGetdispinfoList() constantly runmemberBenj103 Mar '05 - 10:19 

Hello,
 
If this function, OnGetdispinfoList(), contanstly runs on the backgroup, does it slow other process.
 
Nice work.
 
thanks

GeneralRe: OnGetdispinfoList() constantly runmemberPEK4 Mar '05 - 7:44 
Yes, every process that is running is slowing down other processes.
GeneralRe: OnGetdispinfoList() constantly runmemberIsmail Ufuk PAZARBASI11 Mar '05 - 8:48 
It runs when needed, it does not run all the time. What actually happens is that, listview sends this notification when it needs information about an item. LVM_GETITEM, or drawing messages (which, in turn, send LVM_GETITEM to listview) cause this notification to be sent to the listview's parent.
 
No, it doesn't (should not) slow other processes, if you do not intentionally do that, because you just provide information about the item. If you check out file system each time you receive LVN_GETDISPINFO, then you may slowdown.
QuestionWhat about icons not in the first column?memberrbid18 Jan '05 - 0:09 
Nice article. (myVode=5;)
 
How can I set an icon for other column than the first column? (e.g. On the last column?)
 
The code for LVN_GETDISPINFO as you explained, will deal only
with the first column icons.
 
Any hint? Is this possible?
 

 
-- Ricky Marek (AKA: rbid)
-- "Things are only impossible until they are not" --- Jean-Luc Picard
 
My articles
 

AnswerRe: What about icons not in the first column?memberPEK18 Jan '05 - 0:59 
You just need to add the LVS_EX_SUBITEMIMAGES flag, and most of the work is done. Something like this:
 
ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_SUBITEMIMAGES );
 
Handling the LVN_GETDISPINFO message isn’t much harder. You just need to check which sub item you working with. To set image 3 on item 2, sub item 1, you do something like this:
 
if( pItem->mask & LVIF_IMAGE) 
{
	if(pItem->iSubItem == 1)
	{
		if(pItem->iItem == 2)
			pItem->iImage = 3;
	}
}

GeneralRe: What about icons not in the first column?memberrbid18 Jan '05 - 20:19 
Thanks for the solution. (I did not know the existence of LV_EX_SUBITEMIMAGES.)
 
Now in my MFC code I have: (Which is the same as your code)
    ...
    <font color=#FF0000>// m_graphListCtrl is an Owner Draw List Control.
    // m_listCount is the size of the virtual list to display.</font>
    m_graphListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_CHECKBOXES | LVS_EX_SUBITEMIMAGES);
    m_graphListCtrl.SetItemCountEx(m_listCount);
    ...
Handling the LVN_GETDISPINFO is also easy as you mentioned Smile | :)
 
Have a nice day
 

 
-- Ricky Marek (AKA: rbid)
-- "Things are only impossible until they are not" --- Jean-Luc Picard
 
My articles
 

GeneralRe: What about icons not in the first column?memberrbid18 Jan '05 - 22:32 
As far I saw, the image is left-aligned, and if you have gridlines, the image's left-most pixels are cutted by the grig-line.
 
Is there a way (without subclasing or custom-draw) to change the alignment of the image (not in the first column)?
 
-- Ricky Marek (AKA: rbid)
-- "Things are only impossible until they are not" --- Jean-Luc Picard
 
My articles
 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 5 Aug 2004
Article Copyright 2004 by PEK
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid