Virtual List control---load big data rows

Source: Internet
Author: User

The usual use of the column Listview/listctrl control, are only rows to hundreds of rows of data, until today, in the project encountered on the 10W magnitude of data bar, finally feel the common load of hardship, then to the Internet to find a pass, found the same, reproduced the more detailed, the code behind the use of M_items, a list of data structures for the stored list,

Although this article is exhaustive, another one is to do a demo,

Demo

First, what is a virtual list control

A virtual list control refers to a list control with a lvs_ownerdata style ...

Second, why use the virtual list control

We know that it is common to use the list control CListCtrl, to call InsertItem to insert the data to be displayed in the list, and then we don't have to care where the data is, because the control itself opens up memory space to hold the data. Now suppose we want to display a database with a large amount of information, with hundreds of thousands of records. There are usually two ways to solve this problem: 1 is to insert only a small amount of data in the Listctrl, such as 100, and then through the [previous] [next] two buttons to control, a moment is displayed only from XXX to xxx+100 records. 2 is to insert all the data into Listctrl, and then let the user scroll to see the data. Undoubtedly, many users prefer to use the second way, especially for the sorted data, the user can only use the keyboard to enter the beginning of a line of characters, it is possible to quickly navigate to a row. However, if you do this, the process of insertitem inserting data will be lengthy, and users will see that the Listctrl refresh is also slow, and that all the data is in memory and consumes a lot of memory, which is almost unbearable when the data reaches tens of thousands of times.

For this reason, MFC provides support for virtual lists in particular. A virtual list looks like a normal Listctrl, but instead of inserting data through InsertItem, it just knows how much data you should display. But how does it know what data to display? The secret is that when a list control needs to display a certain data, it is going to the parent window. Assuming that the list control contains 100 elements, the 10th to 20th element (row) is visible. When the list control is redrawn, it first requests the parent window to give it the data of the 10th element, and when the parent window receives the request, the data information is populated into a structure provided by the list, and the list can be used to display the 10th data, and the list will continue to request the next data.

Under the virtual style, Listctrl can support up to a DWORD of data items. (The default Listctrl control supports a maximum of int data items). However, the biggest advantage of a virtual list is not this, but rather the fact that it only needs to keep a very small amount of data in memory, which speeds up the display. Therefore, using a list control to display a large database is best for a virtual list.

Not only does CListCtrl provide the functionality of virtual lists, but MFC's CListView classes also have the same functionality.

Third, the message of the virtual list control


The virtual list sends a total of three messages to the parent window: it sends a LVN_GETDISPINFO message when it needs data. This is the most important news. When the user tries to find an element, it sends a LVN_ODFINDITEM message, and the message is Lvn_odcachehint, which is used to buffer the data, which is rarely used.

Virtual list controls are very simple to use. It has only three related messages in total, and if you use CListCtrl directly, you should respond to these three messages in a dialog box. If you use the CListCtrl derived class, you can respond to the three message's reflection message in a derived class. The three messages were:

(1) Lvn_getdispinfo control requests a data
(2) Lvn_odfinditem Find a data
(3) Lvn_odcachehint buffering a part of the data

The message we must respond to IS (1), in most cases to respond (2), in rare cases a response is required (3)

Iv. How to use the virtual list control

1, first to create a control, create a virtual list and create a normal CListCtrl almost. Add a list control resource to the Resource editor first. Then select the Owner Data property and then bundle it with a CListCtrl variable. Add columns, add ImageList, and so on, just as you would with normal Listctrl.

2. Add elements to the virtual list. Suppose M_list is the control variable for this list. Typically, this adds data:

M_list. InsertItem (0, _t ("Hello World"));

But for virtual lists, you can't do this. Just tell the list how many data you have:

Show 100 rows in total
M_list. Setitemcount (100);

3, processing its notification message.

V. How to respond to a message from a virtual list

1. Processing LVN_GETDISPINFO notification messages

When a virtual list control needs some data, it sends a LVN_GETDISPINFO notification message to the parent window indicating that a data request is being requested. So the owner window of the list (or itself) must handle this message. For example, the case of a derived class (Cmylistctrl is a virtual List class object):

This is dealing with reflection messages.
Begin_message_map (Cmylistctrl, CListCtrl)
{{Afx_msg_map (Cmylistctrl)
On_notify_reflect (Lvn_getdispinfo, Ongetdispinfo)
}}afx_msg_map
End_message_map ()

In Lvn_getdispinfo's handler function, you must first check what data is requested by the list, and the possible values are:

(1) Lvif_text must be filled with pszText
(2) Lvif_image must be filled with iImage
(3) Lvif_indent must be filled with iindent
(4) Lvif_param must be filled with LParam
(5) Lvif_state must be filled with state

According to its request, fill in the required data.

================= Example Code =====================================

Here is an example that fills in the text and image information for a data item that is required by the list:

lv_dispinfo* Pdispinfo = (lv_dispinfo*) pnmhdr;
lv_item* pitem= & (Pdispinfo)->item;

int iitemindx= pitem->iitem;

if (Pitem->mask & Lvif_text)//String buffer valid
{
Switch (Pitem->isubitem) {
Case 0://Fill in the name of the data item
lstrcpy (Pitem->psztext,M_items[Iitemindx].m_stritemtext];
Break
Case 1://Padding subkey 1
lstrcpy (Pitem->psztext,M_items[Iitemindx].m_strsubitem1text];
Break
Case 2://Padding subkey 2
lstrcpy (Pitem->psztext,M_items[Iitemindx].m_strsubitem2text];
Break
}
}
/* Note that Lstrcpyn is used in most cases, because the maximum number of copied characters is given by Pitem->cchtextmax:
Lstrcpyn (Pitem->psztext, text, Pitem->cchtextmax);
*/

if (Pitem->mask & lvif_image)//Whether the image is requested
Pitem->iimage= M_items[iitemindx].m_iimageindex;

Even information about whether a row of data is selected (when there is a checkbox) needs to be maintained by the user himself, for example:
Do you want to display the selection information for this row?
if (ischeckboxesvisible ())//Custom function
{
Pitem->mask |= lvif_state;
Pitem->statemask = Lvis_stateimagemask;

if (m_database[itemid].m_checked)
{
Pitem->state = Indextostateimagemask (2);
}
Else
{
Pitem->state = Indextostateimagemask (1);
}
}


2. Handling Lvn_odfinditem Messages

In the Explorer, navigate to a folder, will display a lot of files, if you press the keyboard's ' a ', then the Explorer will automatically find the name "a" in the folder or file, and select the file. Continue to press A, if there are other files whose names begin with ' A ', the next file is selected. If you enter "AB", the file that starts with ' AB ' is selected. This is the auto-find feature of the list control.

When the virtual list receives a Lvm_finditem message, it also sends this message to notify the parent window to find the target element. The information to be searched is given through the lvfindinfo structure. It is a member of the NMLVFINDITEM structure. When the data to be searched is found, the index (line number) of the data should be returned, or 1 if not found.

As an example of a dialog box, the response function is roughly as follows:

================= Example Code =====================================
void Cvirtuallistdlg::onodfinditemlist (nmhdr* pnmhdr, lresult* pResult)
{
PNMHDR inside is the information to find the element
The line number of the target element to be selected is the last to be saved in PResult, which is the key!

nmlvfinditem* Pfindinfo = (nmlvfinditem*) pnmhdr;

/* Pfindinfo->istart is the starting position of the lookup, one until the end, then from the beginning, if not found suitable, eventually stay in istart*/

*presult =-1;

Do you want to search by text?
if ((Pfindinfo->lvfi.flags & lvfi_string) = = 0)
{
Return
}

This is the string we're looking for.
CString searchstr = pfindinfo->lvfi.psz;

int startpos = pfindinfo->istart;//Save starting position

Determine if the last line
if (Startpos >= m_list. GetItemCount ())
startpos = 0;

int currentpos=startpos;

Start finding
Do
{
if (_tcsnicmp (M_database[currentpos].m_name,
Searchstr, Searchstr. GetLength ()) = = 0)
{
Select this element to stop finding
*presult = Currentpos;
Break
}

currentpos++;

Start from the beginning
if (Currentpos >= m_list. GetItemCount ())
Currentpos = 0;

}while (Currentpos! = startpos);
}

Obviously, if there is a lot of data, you must implement a quick Find method.

You can refer to MSDN for a detailed description of the information in Pfindinfo->lvfi.

3, processing Lvn_odcachehint message.

If we read data from a database or other place is slow, we can use this message, bulk read some of the data, and then according to the request, provided to the virtual list. The purpose of the Lvn_odcachehint message is to give the program a chance to buffer the data. To improve the performance of the program.

================= Example Code =====================================
Use the ClassWizard overload onchildnotify function to check if the message is Lvn_odcachehint, and then prepare the buffered data:

nmlvcachehint* Pcachehint=null;

nmhdr* PhDr = (nmhdr*) LParam;

if (Phdr->code = = Lvn_odcachehint)
{
Pcachehint= (nmlvcachehint*) PhDr;
Custom function to prepare the specified range of data into the buffer
Prepcache (Pcachehint->ifrom, Pcachehint->ito);
}
else ...

Note that if the message is not lvn_odcachehint, it is passed to the base class for processing.

V. How to modify the data displayed by Listctrl.

Since the program maintains the data itself, simply modify the data in the database and call the Clistctrl::redrawitems function to redraw it.

Vi. selection Status and selection box for data

CListCtrl can display the checkbox selection box. In some cases it is useful. For normal Listctrl, the user can use the mouse to modify the selection state of an element, but not for the virtual list. You must handle some messages yourself, and then save the selected state of your data yourself:

void Cvirtuallistdlg::togglecheckbox (int item)
{
m_database[item].m_checked =!m_database[item].m_checked;
M_list. Redrawitems (item, item);
}

Process the Lvn_keydown message and add a response to the SPACEBAR to toggle the selection state:

void Cvirtuallistdlg::onkeydownlist (nmhdr* pnmhdr, lresult* pResult)
{
lv_keydown* Plvkeydown = (lv_keydown*) pnmhdr;

if (Plvkeydown->wvkey = = vk_space)
{
int item = m_list. Getselectionmark ();
if (item! =-1)
Togglecheckbox (item);
}

*presult = 0;
}

Then process the Nm_click message:

void Cvirtuallistdlg::onclicklist (nmhdr* pnmhdr, lresult* pResult)
{
nmlistview* Pnmlistview = (nm_listview*) pnmhdr;

Lvhittestinfo Hitinfo;
hitinfo.pt = pnmlistview->ptaction;

int item = m_list. HitTest (&hitinfo);

if (item! =-1)
{
See if the mouse clicks on the check box?
if ((Hitinfo.flags & lvht_onitemstateicon)! = 0)
{
Togglecheckbox (item);
}
}

*presult = 0;
}

Seven, remark:

1. The virtual list cannot be sorted.

2, one of the advantages of virtual table is easy to maintain and database synchronization. It is easy and efficient to modify the data in the database, and then redraw the list.

3. Another advantage of virtual tables is that data can be generated as needed. For example, add an uplink number to a column.

Virtual List control---load big data rows

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.