There's more to it than that. It's been a while since I set one up so I don't remember the details, but from the sound of your problem, you don't have it implemented correctly.
My implementation is that view receives data from read thread, adds it to the document and loads the list from document data. So I have all my data in one place in document class and I think it is quite in line with doc/view architecture. I would be interested to hear about anything in particular that might sound incorrect to you?
My implementation is that view receives data from read thread, adds it to the document and loads the list from document data. So I have all my data in one place in document class and I think it is quite in line with doc/view architecture. I would be interested to hear about anything in particular that might sound incorrect to you?
I was talking about your implementation of your virtual list control. As I said, it's been a while since I set one up, but there shouldn't be any significant time involved in loading a lot of records into one.
Check out the attached LVSelState project. It uses a virtual listview to display list items.
The user can change the number of virtual items up to 1M items. The virtual list control gets it's data from a std::list and the list is populated from a 2nd thread.
By default, the project waits until all the items are in the control until the control is refreshed, but you can change that behavior by commenting out the CWaitCursor and LockWindowUpdate calls.
Code:
HRESULT Populate( CListCtrl& ctlList )
{
HRESULT hr = S_OK;
// Add a wait cursor
// CWaitCursor wait;
long lIndex = 0;
LVITEM lvitem = { 0 };
int iItem = 0, iActualItem = 0;
lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
// Lock the List Control window so it doesn't look
// like crap while filling
// ctlList.LockWindowUpdate();
// Lock the list
CAutoLockT< CLVItemDataList > lock( &m_LVItemDataList );
// Cycle through the list and add each item into the list control
for(CLVItemDataList::iterator it = m_LVItemDataList.begin();
it < m_LVItemDataList.end();
it++)
{
CLVItemData* pLVItemData = (*it);
lvitem.iItem = iItem;
lvitem.iSubItem = 0;
lvitem.lParam = reinterpret_cast<LPARAM>(pLVItemData);
// Tell the list control to become 'Virtual' and request display
// data from the lvitem.lParam.
// See CLVSelStateDlg::OnLvnGetdispinfoList for where this happens
lvitem.iImage = I_IMAGECALLBACK;
lvitem.pszText = LPSTR_TEXTCALLBACK;
lvitem.cchTextMax = MAX_LVITEMLEN;
// Insert the item
ctlList.InsertItem(&lvitem);
// Set the text for each column (all virtual callbacks)
ctlList.SetItemText(iItem, 0, LPSTR_TEXTCALLBACK);
ctlList.SetItemText(iItem, 1, LPSTR_TEXTCALLBACK);
ctlList.SetItemText(iItem, 2, LPSTR_TEXTCALLBACK);
iItem++;
// Check if user cancelled operation
if( WAIT_OBJECT_0 == WaitForSingleObject( GetShutdownEvent(), 0 ) )
{
return hr;
}
// Pump messages to allow cancel button click
// during control filling. Populating the control
// with thousands of records takes time, so we need
// to process messages to handle the cancel button
// and close messages
if(!ProcessMessages( ))
{
return hr;
}
// Restore the wait cursor
// (if you don't do this, the wait cursor may go
// away after processing messages)
// wait.Restore();
}
// Unlock the List control window
// ctlList.UnlockWindowUpdate();
return hr;
}
My implementation is that view receives data from read thread, adds it to the document and loads the list from document data...
Wait, you are not re-loading entire list after each record is read, are you?
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio: FeinWindows - replacement windows manager for Visual Studio, and more...
Wait, you are not re-loading entire list after each record is read, are you?
Definitely not, when the latest record/row becomes available from file I add it to the document and to the view. There is no refilling of the already loaded data.
The virtual list control gets it's data from a std::list and the list is populated from a 2nd thread.
This caught my eye, I normally don't use std::list with listivew because link list can't be accessed via index unlike std::vector and your code indeed use std::vector as I expected.
I actually don't use this in my code because it is handled by LVN_GETDISPINFO handler anyways. I commented this in your project and works fine too without it.
Originally Posted by Igor Vartanov
The question is: do you or don't you use virtual list?
I think I might be confused with terminology here, more on this below. I took the opportunity to compared my project performance with Arjay's demo project. Here are the results.
My computer takes about 2 seconds to load/populate 7000 rows in Arjay's project.
My own project takes about 2.5 seconds to load 7000 rows from a file I have on disk.
Now the demo project as you see has only 3 columns and my listview has 35 columns. The demo project is not reading any disk file but I am also parsing 27MB file during this time. This makes me pretty happy about my results.
My loading mechanism is actually very similar to Arjay's project but I keep all the list data in CPtrArray instead of std::vector. Makes me think if I am already using virtual list without really know the terminology? All I know is I am definetely not using owner drawn listview style.
So what is the problem at this moment?
You do not get a visual feedback from the list that it is being populated?
Do you scroll your list to the bottom when new item is added? If not – the display is not going to change that much, just the scroll bar.
You do not need to Invalidate(), but, as was noted in one of the firs few replies, you need to call UpdateWindow() to enforce the update.
If it impairs performance, you can do it for every tenth, twenties or fiftieth update.
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio: FeinWindows - replacement windows manager for Visual Studio, and more...
This caught my eye, I normally don't use std::list with listivew because link list can't be accessed via index unlike std::vector and your code indeed use std::vector as I expected.
I actually don't use this in my code because it is handled by LVN_GETDISPINFO handler anyways. I commented this in your project and works fine too without it.
I think I might be confused with terminology here, more on this below. I took the opportunity to compared my project performance with Arjay's demo project. Here are the results.
My computer takes about 2 seconds to load/populate 7000 rows in Arjay's project.
My own project takes about 2.5 seconds to load 7000 rows from a file I have on disk.
Now the demo project as you see has only 3 columns and my listview has 35 columns. The demo project is not reading any disk file but I am also parsing 27MB file during this time. This makes me pretty happy about my results.
My loading mechanism is actually very similar to Arjay's project but I keep all the list data in CPtrArray instead of std::vector. Makes me think if I am already using virtual list without really know the terminology? All I know is I am definetely not using owner drawn listview style.
It doesn't really matter which container you use. std::list would work as well as std::vector (and maybe even yield better performance). I say the container doesn't matter because the container items aren't reference by index in my project. I use the Set[Get]ItemData methods to store/retrieve the pointer to the item directly - the index isn't use.
One thing to try for performance is to use a std::list and instead of having the list store a pointer to the item, try it with storing the actual item. You'll need to write a copy constructor for the items but it might be more performant that way.
So what is the problem at this moment?
You do not get a visual feedback from the list that it is being populated?
My original issue of feedback was resolved my cutting down on the number of messages I post to main thread. I was just following up on Arjay's demo and clearing some thoughts about virtual lists
Originally Posted by Arjay
It doesn't really matter which container you use. std::list would work as well as std::vector (and maybe even yield better performance). I say the container doesn't matter because the container items aren't reference by index in my project. I use the Set[Get]ItemData methods to store/retrieve the pointer to the item directly - the index isn't use.
One thing to try for performance is to use a std::list and instead of having the list store a pointer to the item, try it with storing the actual item. You'll need to write a copy constructor for the items but it might be more performant that way.
I agree the container doesn't matter as long as it is not CArray object because it could reallocates itself if expanded and the pointers stored in list could become old and invalid. std::list is a link list and is good to go!
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.