• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            預(yù)備性閱讀
            在閱讀本文之前,建議先對列表視圖控件和系統(tǒng)外殼有一個基本的了解。建議閱讀以下SDK文章

            Shell FAQ
            List-View Controls Overview
            Using List-View Controls
            Customizing a Control's Appearance Using Custom Draw
            創(chuàng)建應(yīng)用程序
            使用MFC應(yīng)用程序向?qū)?chuàng)建一個SDI應(yīng)用程序,在最后一步選擇視圖的基類為CListView。創(chuàng)建完成之后,在資源中去掉保存、編輯和打印等功能的菜單和工具欄按鈕(因為這些功能沒有實現(xiàn))。

            虛列表的創(chuàng)建
            本文采用虛列表技術(shù),使得顯示信息是在第一次顯示的時候才被獲取。為了創(chuàng)建虛列表,在創(chuàng)建之前需要指定列表的風(fēng)格

            BOOL CPicViewView::PreCreateWindow(CREATESTRUCT& cs)
            {
            ??? cs.style&=~LVS_TYPEMASK;
            ??? cs.style|=LVS_ICON|LVS_OWNERDATA;
            ??? return CListView::PreCreateWindow(cs);
            }
            同時,因為列表項的Overlay圖標(biāo)也是被動態(tài)獲取的,所以需要設(shè)置動態(tài)Overlay圖標(biāo)

            void CPicViewView::OnInitialUpdate()
            {
            ??? CListView::OnInitialUpdate();
            ??? GetListCtrl().SetCallbackMask(LVIS_OVERLAYMASK);
            }

            緩存顯示信息
            在列表需要顯示一個范圍的項目之前,列表會發(fā)送LVN_ODCACHEHINT通知,應(yīng)用程序可以捕獲這個消息來緩存部分列表的顯示信息,以提高性能。

            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;
            }
            在列表需要顯示一個項目之前,列表會發(fā)送LVN_GETDISPINFO通知,應(yīng)用程序可以捕獲這個消息來提供項目的顯示信息。如果顯示時需要顯示的列表項在緩存中,那么可以從緩存中獲取顯示信息。否則需要重新從文件獲得。

            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;
            }


            文件圖標(biāo)的顯示
            默認(rèn)情況下,列表項的圖標(biāo)就是其系統(tǒng)圖標(biāo)。首先獲得系統(tǒng)圖像列表

            int CPicViewView::OnCreate(LPCREATESTRUCT lpCreateStruct)
            {
            ??? if (CListView::OnCreate(lpCreateStruct) == -1)
            ??????? return -1;
            ??? HRESULT hr = SHGetMalloc(&m_pMalloc); if(FAILED(hr)) return -1;
            ??? hr = SHGetDesktopFolder(&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;
            }

            然后在獲取文件信息時,從文件獲得其圖標(biāo)在系統(tǒng)圖像列表中的索引。

            如果列表項是圖像文件,并且從文件成功載入圖像,那么使用自畫功能以替換默認(rèn)的圖標(biāo)。

            void CPicViewView::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
            {
            ??? LPNMLVCUSTOMDRAW lpNMCustomDraw = (LPNMLVCUSTOMDRAW) pNMHDR;
            ??? switch(lpNMCustomDraw ->nmcd.dwDrawStage) {
            ??????? case CDDS_PREPAINT : *pResult=CDRF_NOTIFYITEMDRAW;return;
            ??????? case CDDS_ITEMPREPAINT:*pResult=CDRF_NOTIFYPOSTPAINT;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;
            }

            上面的代碼是使用獲取的文件顯示信息中的圖像,在列表項圖標(biāo)的區(qū)域畫圖。

            獲取顯示信息
            為了緩存列表項的顯示信息,或者顯示列表項,需要獲取列表項的文字、圖標(biāo)、Overlay圖標(biāo)和縮略圖等信息。這里使用了ILCombine來把緩存中的相對PIDL轉(zhuǎn)化為完整的Pidl,再據(jù)此獲得文件的完整路徑,然后調(diào)用OleLoadPicturePath函數(shù)載入圖像。

            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);
            ??? }
            }

            緩存目錄的數(shù)據(jù)
            在更改目錄時,需要重建目錄內(nèi)容的緩存。這包括目錄的pidl和IShellFolder接口指針,目錄內(nèi)容的相對pidl,以及列表項的顯示信息(基于性能上的考慮,列表項的顯示信息是在接收到LVN_ODCACHEHINT通知的時候緩存的)。

            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());
            ??? }
            }

            ?

            打開文件夾
            本應(yīng)用程序顯示文件夾的內(nèi)容而不是顯示文檔的內(nèi)容,所以我重載了打開文件時的處理,顯示目錄選擇對話框而不是文件打開對話框。

            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);
            ??????? }
            ??? }
            }

            注意從外殼調(diào)用獲得的PIDL一般都需要調(diào)用ILFree或者IMalloc::Free釋放。一個例外是調(diào)用函數(shù)SHBindToParent獲得的相對pidl,因為它是輸入的參數(shù)完整pidl的一部分,所以不必另外釋放。

            在新建或者打開“文件”時候,文檔需要通知視圖當(dāng)前文件夾的更改,這是通過調(diào)用CDocument::UpdateAllViews和重載CView::OnUpdate實現(xiàn)的。視圖對這個通知的處理是清除上一個目錄的緩存數(shù)據(jù),緩存新目錄的數(shù)據(jù),以及更新文檔標(biāo)題。
            ?

            打開文件或者目錄
            為了使用方便,雙擊列表項時可以在同一窗口打開子目錄,或者調(diào)用系統(tǒng)的默認(rèn)處理程序打開文件。如果文件是快捷方式,那么打開快捷方式的目標(biāo)。

            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);
            ??? }
            }
            ?

            性能的優(yōu)化
            為了更好的用戶體驗,可以使用自定義的圖標(biāo)大小(這需要完全自行繪制列表項的圖標(biāo)區(qū)域),用單獨的線程來載入圖像,或者使用調(diào)整到圖標(biāo)大小的縮略圖緩沖(這樣每次繪制時不必拉伸圖像)。但是這超出了本文的范圍。有興趣的讀者可以自己試一下。

            參考
            需要更多信息的話,可以參考

            Shell FAQ
            List-View Controls Overview
            Using List-View Controls
            Customizing a Control's Appearance Using Custom Draw
            本文來自焦點核(X)軟件安全技術(shù)網(wǎng),原文地址:http://www.xfocusx.com

            91精品国产91久久久久久青草| AV无码久久久久不卡蜜桃| 2021少妇久久久久久久久久| 国产精品久久久香蕉| 三级片免费观看久久| 久久久久国产| 欧美色综合久久久久久| 久久久国产一区二区三区| 久久精品成人影院| 日日狠狠久久偷偷色综合96蜜桃 | 亚洲乱码精品久久久久..| 日日狠狠久久偷偷色综合0| 久久这里只有精品视频99| 久久亚洲av无码精品浪潮| 亚洲午夜精品久久久久久app| 久久综合九色综合久99| 欧美一级久久久久久久大| 久久久久亚洲精品天堂久久久久久| 久久噜噜久久久精品66| 亚洲v国产v天堂a无码久久| 久久天天躁狠狠躁夜夜不卡| 久久精品国产男包| 国产产无码乱码精品久久鸭| 久久精品中文字幕久久| 久久久久亚洲AV无码去区首| 三级片免费观看久久| 色婷婷综合久久久久中文| 国产精品久久久久9999高清| 7国产欧美日韩综合天堂中文久久久久| 国产精品激情综合久久| 久久久久国产一级毛片高清板| 久久久国产视频| 亚洲国产另类久久久精品黑人 | 国产成人精品久久一区二区三区av| 四虎国产精品免费久久久| 久久久精品人妻无码专区不卡 | 久久精品国产亚洲Aⅴ香蕉| 久久精品免费全国观看国产| 久久久免费精品re6| 久久久精品人妻无码专区不卡| 综合网日日天干夜夜久久|