CMFCShellListCtrl是个很有用的新类,用它可以直接构造出文件/文件夹选择页面,先看看结果图
1.替换中文列名并改变列宽及居中显示
CMFCShellListCtrl创建出来的时候默认列名是英文的,这样改成中文:
- 从CMFCShellListCtrl派生出自定义类
class CMyShelistCtrl : public CMFCShellListCtrl
- 定义CMyShelistCtrl变量
- 控件风格改为Report
m_ShelListCtrl.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
- 重载虚函数
virtual void OnSetColumns();
- 重载函数写
LVCOLUMN lvColumn; lvColumn.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH ; LPWSTR sName[4] = {_T("名称"),_T("大小"),_T("类型"),_T("修改")}; int nWidth[4] = {200,100,100,200}; for(int i=0;i<4;i++) { lvColumn.pszText = sName[i]; lvColumn.cx = nWidth[i]; lvColumn.fmt = LVCFMT_CENTER; SetColumn(i,&lvColumn); }
- END
2.获得鼠标单击控件列出的文件夹/文件的名字
- 响应控件NM_CLICK事件
ON_NOTIFY(NM_CLICK, IDC_MFCSHELLLIST, &CShellListCtrlDlg::OnNMClickMfcshelllist)
- 响应函数里添加代码
void CShellListCtrlDlg::OnNMClickMfcshelllist(NMHDR *pNMHDR, LRESULT *pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); // TODO: Add your control notification handler code here NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { m_sCurrName = m_ShelListCtrl.GetItemText(pNMListView->iItem, pNMListView->iSubItem); m_FileNameEdit.SetWindowText(m_sCurrName); } *pResult = 0; }
- 其中m_sCurrName即为点击获得的文件夹/文件名END
3.过滤要显示的文件夹/文件
- 重载虚函数
virtual HRESULT EnumObjects (LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent);
- 填写下面的代码
HRESULT CMyShelistCtrl :: EnumObjects (LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent) { ASSERT_VALID(this); LPENUMIDLIST pEnum = NULL; HRESULT hRes = pParentFolder->EnumObjects(NULL, m_nTypes, &pEnum); if (SUCCEEDED(hRes) && pEnum != NULL) { LPITEMIDLIST pidlTemp; DWORD dwFetched = 1; LPAFX_SHELLITEMINFO pItem; //enumerate the item's PIDLs while (pEnum->Next(1, &pidlTemp, &dwFetched) == S_OK && dwFetched) { LVITEM lvItem; ZeroMemory(&lvItem, sizeof(lvItem)); //fill in the TV_ITEM structure for this item lvItem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; //AddRef the parent folder so it's pointer stays valid pParentFolder->AddRef(); //put the private information in the lParam pItem = (LPAFX_SHELLITEMINFO)GlobalAlloc(GPTR, sizeof(AFX_SHELLITEMINFO)); pItem->pidlRel = pidlTemp; pItem->pidlFQ = afxShellManager->ConcatenateItem(pidlParent, pidlTemp); pItem->pParentFolder = pParentFolder; lvItem.lParam = (LPARAM)pItem; lvItem.pszText = _T(""); lvItem.iImage = OnGetItemIcon(GetItemCount(), pItem); //determine if the item is shared DWORD dwAttr = SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK; pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &dwAttr); if (dwAttr & SFGAO_SHARE) { lvItem.mask |= LVIF_STATE; lvItem.stateMask |= LVIS_OVERLAYMASK; lvItem.state |= INDEXTOOVERLAYMASK(1); //1 is the index for the shared overlay image } if (dwAttr & SFGAO_GHOSTED) { lvItem.mask |= LVIF_STATE; lvItem.stateMask |= LVIS_CUT; lvItem.state |= LVIS_CUT; } if (dwAttr & SFGAO_FOLDER) { } else { TCHAR szPath [MAX_PATH]; if (SHGetPathFromIDList(pItem->pidlFQ, szPath)) { CFileStatus fs; if (CFile::GetStatus(szPath, fs)) { CString s = szPath; int n = s.ReverseFind('.'); if(n!=-1) { s = s.Mid(n+1); s.MakeLower(); if(s == _T("exe"))//改写扩展名就可以过滤 continue; } } } } int iItem = InsertItem(&lvItem); if (iItem >= 0) { // Set columns: const int nColumns = m_wndHeader.GetItemCount(); for (int iColumn = 0; iColumn < nColumns; iColumn++) { SetItemText(iItem, iColumn, OnGetItemText(iItem, iColumn, pItem)); } } dwFetched = 0; } pEnum->Release(); } return hRes; }
- 过滤之后结果
END
4.只显示文件夹或文件或都显示
m_ShelListCtrl.SetItemTypes(SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);//看名字就应该知道怎么用吧