Display folder thumbnails using virtual list and self-Painting

Source: Internet
Author: User

This example demonstrates the virtual list and self-painting functions of the list control, as well as the usage of some System Shell functions and interfaces.

Click here to download the code of this article. If something goes wrong while compiling the sample program, you need to go to the http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ to upgrade your header files and library files

Preliminary reading

Before reading this article, we recommend that you have a basic understanding of the List View Controls and system shell. Read the following SDK articles.

  • Shell FAQ
  • List-View Controls Overview
  • Using list-View Controls
  • Customizing a control's appearance using custom draw
Create an application

Use the MFC Application Wizard to create an SDI application. In the last step, select clistview as the base class of the view. After the creation is complete, remove the menu and toolbar buttons for saving, editing, and printing functions in the resource (because these functions are not implemented ).

Create a virtual list

This article uses the virtual list technology, so that the display information is obtained only when it is displayed for the first time. Before creating a virtual list, you must specify the style of the list.

Bool cpicviewview: precreatewindow (createstruct & CS)
{
CS. Style & = ~ Lvs_typemask;
CS. Style | = lvs_icon | lvs_ownerdata;
Return clistview: precreatewindow (CS );
}
At the same time, because the overlay icon of the list item is also dynamically obtained, you need to set the dynamic overlay icon

Void cpicviewview: oninitialupdate ()
{
Clistview: oninitialupdate ();
Getlistctrl (). setcallbackmask (lvis_overlaymask );
}

Cache display information

Before a project within a specified range needs to be displayed in the list, the list will send an lvn_odcachehint notification. The application can capture this message to cache the display information of some lists to improve performance.

Void cpicviewview: onodcachehint (nmhdr * pnmhdr, lresult * presult)
{
Nmlvcachehint * pcachehint = (nmlvcachehint *) pnmhdr;
Prepcache (0, min (5, m_arpfolderitems.getsize ()));
Prepcache (pcachehint-> ifrom, pcachehint-> ITO );
Prepcache (max (0, m_arpfolderitems.getsize ()-5), m_arpfolderitems.getsize ());
* Presult = 0;
}
Before a project needs to be displayed in the list, the list will send an lvn_getdispinfo notification. The application can capture this message to provide project display information. If the list items to be displayed are in the cache, you can obtain the display information from the cache. Otherwise, you need to obtain it from the file again.

Void cpicviewview: ongetdispinfo (nmhdr * pnmhdr, lresult * presult)
{
Lv_dispinfo * pdispinfo = (lv_dispinfo *) pnmhdr;
If (pdispinfo-> item. iItem =-1) return;
Hresult hR = s_ OK;
Lpcitemidlist pidlitem = m_arpfolderitems [pdispinfo-> item. iItem];
Cfolderiteminfo * pfolderiteminfo = finditemincache (pidlitem );
Bool bcached = true;
If (pfolderiteminfo = NULL ){
Bcached = false;
Pfolderiteminfo = new cfolderiteminfo;
Getiteminfo (pidlitem, pfolderiteminfo );
}
If (pdispinfo-> item. Mask & lvif_text ){
Lstrcpyn (pdispinfo-> item. psztext, pfolderiteminfo-> tszdisplayname, pdispinfo-> item. cchtextmax );
}
If (pdispinfo-> item. Mask & lvif_image ){
Pdispinfo-> item. iimage = pfolderiteminfo-> iicon;
}
If (pdispinfo-> item. Mask & lvif_state ){
Pdispinfo-> item. State = pfolderiteminfo-> state;
}
If (! Bcached)
Delete pfolderiteminfo;
* Presult = 0;
}

File icon display

By default, the icon of the list item is its System icon. First, obtain the system image list.

Int cpicviewview: oncreate (maid)
{
If (clistview: oncreate (lpcreatestruct) =-1)
Return-1;
Hresult hR = shgetmalloc (& m_pmalloc); If (failed (HR) Return-1;
HR = shgetdomaintopfolder (& m_psfdesktop); If (failed (HR) Return-1;
Shfileinfo shfi;
Zeromemory (& shfi, sizeof (shfileinfo ));
Himagelist HI = (himagelist) shgetfileinfo (null, 0, & shfi, sizeof (shfileinfo), shgfi_icon | shgfi_sysiconindex | shgfi_smallicon );
Getlistctrl (). setimagelist (cimagelist: fromhandle (HI), lvsil_small );
Hi = (himagelist) shgetfileinfo (null, 0, & shfi, sizeof (shfileinfo), shgfi_icon | shgfi_sysiconindex | shgfi_largeicon );
Getlistctrl (). setimagelist (cimagelist: fromhandle (HI), lvsil_normal );
Return 0;
}

Then, when obtaining the file information, obtain the index of its icon in the system image list from the file.

If the list item is an image file and the image is successfully loaded from the file, use the self-painting function to replace the default icon.

Void cpicviewview: oncustomdraw (nmhdr * pnmhdr, lresult * presult)
{
Lpnmlvcustomdraw lpnmcustomdraw = (lpnmlvcustomdraw) pnmhdr;
Switch (lpnmcustomdraw-> nmcd. dwdrawstage ){
Case cdds_prepaint: * presult = cdrf_policyitemdraw; return;
Case cdds_itemprepaint: * presult = cdrf_policypostpaint; return;
Case cdds_itempostpaint:
{
Int iItem = lpnmcustomdraw-> nmcd. dwitemspec;
If (Iitem =-1 ){
* Presult = cdrf_dodefault; return;
}
Cfolderiteminfo * piteminfo = finditemincache (m_arpfolderitems [iItem]);
If (piteminfo = NULL | piteminfo-> bfailloadpic | piteminfo-> pic. m_ppict = NULL ){
* Presult = cdrf_dodefault; return;
}
Crect recticon;
Getlistctrl (). getitemrect (Iitem, & recticon, lvir_icon );
CDC * PDC = CDC: fromhandle (lpnmcustomdraw-> nmcd. HDC );
Piteminfo-> pic. Render (PDC, recticon, recticon );
}
* Presult = cdrf_newfont; return;
}
* Presult = 0;
}

The above Code uses the image in the obtained file display information to draw a picture in the area of the list item icon.

Get display information

To Cache the display information of a list item or display a list item, you need to obtain text, icons, overlay icons, thumbnails, and other information of the list item. Here, ilcombine is used to convert the relative pidl in the cache to the complete pidl, obtain the complete path of the file accordingly, and then call the oleloadpicturepath function to load the image.

Void cpicviewview: getiteminfo (lpcitemidlist pidl, cfolderiteminfo * piteminfo)
{
Hresult hR = theapp. shgetdisplaynameof (pidl, piteminfo-> tszdisplayname );
Ishellicon * pshellicon = NULL;
HR = m_psffolder-> QueryInterface (iid_ishellicon, (lpvoid *) & pshellicon );
If (succeeded (HR) & pshellicon ){
Pshellicon-> geticonof (pidl, 0, & piteminfo-> iicon );
Pshellicon-> release ();
}
Ishelliconoverlay * pshelliconoverlay = NULL;
HR = m_psffolder-> QueryInterface (iid_ishelliconoverlay, (lpvoid *) & pshelliconoverlay );
If (succeeded (HR) & pshelliconoverlay ){
Int noverlay = 0;
Pshelliconoverlay-> getoverlayindex (pidl, & noverlay );
Piteminfo-> state = indextooverlaymask (noverlay );
Pshelliconoverlay-> release ();
}
Lpitemidlist pidlitemfull = ilcombine (m_pidlfolder, pidl );
If (pidlitemfull ){
If (shgetpathfromidlist (pidlitemfull, piteminfo-> tszpath )){
Uses_conversion;
HR = oleloadpicturepath (
T2ole (piteminfo-> tszpath)
, Null, 0, RGB (255,255,255)
, Iid_ipicture, (lpvoid *) & piteminfo-> pic. m_ppict );
If (failed (HR )){
Piteminfo-> bfailloadpic = true;
Trace ("oleloadpicturepath failed % S/R/N", piteminfo-> tszpath );
}
}
}
M_pmalloc-> free (pidlitemfull );
}
}

Cache directory data

When changing a directory, You need to recreate the cache of the directory content. This includes directory pidl and ishellfolder interface pointers, directory content relative pidl, and list item display information (based on performance considerations, the display information of the list items is cached when the lvn_odcachehint notification is received ).

Lpitemidlist m_pidlfolder;
Ishellfolder * m_psffolder;
Ctypedptrarray <cptrarray, lpitemidlist> m_arpfolderitems;
Ctypedptrmap <cmapptrtoptr, lpitemidlist, cfolderiteminfo *> m_mapcache;
 

Void cpicviewview: enterfolder (lpcitemidlist pidl)
{
Uses_conversion;
M_pidlfolder = ilclone (pidl );
If (m_pidlfolder ){
Lpenumidlist ppenum = NULL;
Lpitemidlist pidlitems = NULL;
Ulong celtfetched;
Hresult hr;
HR = m_psfdesktop-> bindtoobject (m_pidlfolder, null, iid_ishellfolder, (lpvoid *) & m_psffolder );
If (succeeded (HR )){
HR = m_psffolder-> enumobjects (null, shcontf_folders | shcontf_nonfolders, & ppenum );
If (succeeded (HR )){
While (hR = ppenum-> next (1, & pidlitems, & celtfetched) = s_ OK & (celtfetched) = 1 ){
M_arpfolderitems.add (pidlitems );
}
}
}
Getlistctrl (). setitemcount (m_arpfolderitems.getsize ());
}
}

 

Open folder

This application displays the folder content instead of the document content, so I reload the processing when opening the file, display the directory selection dialog box instead of the file opening dialog box.

Void cpicviewapp: onfileopen ()
{
Tchar tszdisplayname [_ max_path];
Tchar tszpathselected [_ max_path];
Lpitemidlist pidlselected = pidlbrowse (m_pmainwnd-> getsafehwnd (), 0, tszdisplayname );
If (pidlselected ){
If (shgetpathfromidlist (pidlselected, tszpathselected )){
Cdocument * pdocument = opendocumentfile (tszpathselected );
Pdocument-> settitle (tszdisplayname );
Ilfree (pidlselected );
}
}
}

Note that the pidl obtained from the shell call generally needs to call ilfree or imalloc: free for release. One exception is the relative pidl obtained by calling the shbindtoparent function, because it is part of the complete pidl input parameter, so it does not need to be released separately.

When creating or opening a file, the document needs to notify the view of changes to the current folder, which is implemented by calling cdocument: updateallviews and reloading cview: onupdate. View processes this notification by clearing the cached data in the previous directory, caching the data in the new directory, and updating the document title.
 

Open a file or directory

For ease of use, you can open subdirectories in the same window when double-clicking the list item, or call the system's default handler to open the file. If the file is a shortcut, open the target shortcut.

Void cpicviewview: ondblclk (nmhdr * pnmhdr, lresult * presult)
{
Lpnmlistview lpnm = (lpnmlistview) pnmhdr;
If (lpnm-> iItem =-1) return;
* Presult = 0;
Hresult hR = s_ OK;
Lpcitemidlist pidlitem = m_arpfolderitems [lpnm-> iItem];
Lpitemidlist pidlitemfull = ilcombine (m_pidlfolder, pidlitem );
Lpitemidlist pidlitemtarget = NULL;
HR = theapp. shgettargetfolderidlist (pidlitemfull, & pidlitemtarget );
If (pidlitemtarget ){
If (theapp. ilisfolder (pidlitemtarget )){
Cfolderchange folderchange;
Folderchange. m_pidlfolder = pidlitemtarget;
Onfolderchange (& folderchange );
}
Else {
Shellexecuteinfo shexecinfo;
Shexecinfo. cbsize = sizeof (shellexecuteinfo );
Shexecinfo. fmask = see_mask_idlist;
Shexecinfo. hwnd = NULL;
Shexecinfo. lpverb = NULL;
Shexecinfo. lpfile = NULL;
Shexecinfo. lpidlist = pidlitemtarget;
Shexecinfo. lpparameters = NULL;
Shexecinfo. lpdirectory = NULL;
Shexecinfo. nshow = sw_maximize;
Shexecinfo. hinstapp = NULL;
Shellexecuteex (& shexecinfo );
}
M_pmalloc-> free (pidlitemtarget );
M_pmalloc-> free (pidlitemfull );
}
}
 

Performance Optimization

For better user experience, you can use a custom Icon size (this requires you to completely draw the icon area of the list item) and load the image using a separate thread, or use a thumbnail buffer that is adjusted to the Icon size (so that the image does not need to be stretched each time it is drawn ). However, this is beyond the scope of this article. If you are interested, you can give it a try.

Reference

For more information, see

  • Shell FAQ
  • List-View Controls Overview
  • Using list-View Controls
  • Customizing a control's appearance using custom draw

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.