【发布时间】:2010-11-21 05:53:26
【问题描述】:
当我尝试实例化 CFileDialog 对象时,它会同时显示文件夹和文件。你如何创建一个单独浏览文件夹的CFileDialog?
【问题讨论】:
标签: mfc visual-c++
当我尝试实例化 CFileDialog 对象时,它会同时显示文件夹和文件。你如何创建一个单独浏览文件夹的CFileDialog?
【问题讨论】:
标签: mfc visual-c++
真的很简单。
使用派生自类CFileDialog的CFolderPickerDialog!
【讨论】:
CFileDialog 无法做到这一点。
您将使用SHBrowseForFolder Function 或包装器,
如CFolderDialog - Selecting Folders.
【讨论】:
SHBrowseForFolder 已经严重过时了。来自备注:“对于 Windows Vista 或更高版本,建议您使用 IFileDialog 和 FOS_PICKFOLDERS 选项而不是 SHBrowseForFolder 函数。这使用选择文件夹模式下的打开文件对话框,是首选实现。”我>
CFileDialog,实际上可以 - 请参阅here。
从 Vista 开始,建议使用 IFileDialog 和 FOS_PICKFOLDERS 选项 (see msdn):
CFileDialog od(TRUE/*bOpenFileDialog*/, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT , NULL, NULL, 0,
TRUE/*bVistaStyle*/);
IFileOpenDialog * openDlgPtr = od.GetIFileOpenDialog();
if ( openDlgPtr != NULL )
{
openDlgPtr->SetOptions(FOS_PICKFOLDERS);
openDlgPtr->Release();
}
od.DoModal();
【讨论】:
就像有人提到的那样,使用CFolderPickerDialog 效果很好。我想举例说明如何使用它,尤其是在使用多选标志时:
CFolderPickerDialog folderPickerDialog(initialFolder, OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING, this,
sizeof(OPENFILENAME));
CString folderPath;
if (folderPickerDialog.DoModal() == IDOK)
{
POSITION pos = folderPickerDialog.GetStartPosition();
while (pos)
{
folderPath = folderPickerDialog.GetNextPathName(pos);
}
}
【讨论】:
从windows vista开始,可以使用Common Item Dialog。
void CQiliRegrvDlg::OnBnClickedSelectDir()
{
HRESULT hr = S_OK;
// Create a new common open file dialog.
IFileOpenDialog *pfd = NULL;
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Set the dialog as a folder picker.
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
if (SUCCEEDED(hr))
{
hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS);
}
// Set the title of the dialog.
if (SUCCEEDED(hr))
{
hr = pfd->SetTitle(L"Folder");
}
// Show the open file dialog.
if (SUCCEEDED(hr))
{
hr = pfd->Show(m_hWnd);
if (SUCCEEDED(hr))
{
// Get the selection from the user.
IShellItem *psiResult = NULL;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
PWSTR pszPath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr))
{
m_appDir = pszPath;
SetDlgItemText(IDC_STATIC, m_appDir);
CoTaskMemFree(pszPath);
}
psiResult->Release();
}
}
}
pfd->Release();
}
}
【讨论】:
在我看来,您要的答案在
的代码中CMFCPropertyGridFileProperty::OnClickButton(CPoint /*point*/)
的
<Your Visual Studio installation folder>\VC\atlmfc\src\mfc\afxpropertygridctrl.cpp
文件。
如果您无法访问代码,我将发布它的基本部分:
CString strPath = m_varValue.bstrVal;
BOOL bUpdate = FALSE;
if (m_bIsFolder)
{
if (afxShellManager == NULL)
{
CWinAppEx* pApp = DYNAMIC_DOWNCAST(CWinAppEx, AfxGetApp());
if (pApp != NULL)
{
pApp->InitShellManager();
}
}
if (afxShellManager == NULL)
{
ASSERT(FALSE);
}
else
{
bUpdate = afxShellManager->BrowseForFolder(strPath, m_pWndList, strPath);
}
}
else
{
CFileDialog dlg(m_bOpenFileDialog, m_strDefExt, strPath, m_dwFileOpenFlags, m_strFilter, m_pWndList);
if (dlg.DoModal() == IDOK)
{
bUpdate = TRUE;
strPath = dlg.GetPathName();
}
}
如您所见,当想要打开一个对话框来选择文件夹时,Microsoft 本身并不使用 Cfiledialog 类。
要使用这样的代码,您的应用程序类必须派生自 CWinAppEx,而不是 CWinApp
【讨论】:
其实有办法做到这一点——我在codeguru: "Selected files and folders in CFileDialog"找到了
如果您愿意自己实现 CFileDialog,例如:
class CMyFileDialog : public CFileDialog
您可以添加以下代码,它应该可以工作(它与codeguru example略有不同):
// This code overrides the OnNotify message of the CFileDialog
// and catches the CDN_SELCHANGE, this way you can also do
// something with the selected folders.
BOOL CMyFileDialog::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
NMHDR* pNotificationParam = (NMHDR*)lParam;
// Check that we got to the selection change notification.
int code = pNotificationParam->code;
if (code == CDN_SELCHANGE)
{
CStringArray theSelection;
GetListControllSelectedItems(theSelection);
// Do as you want with theSelection.
}
return CFileDialog::OnNotify(wParam, lParam, pResult);
}
// The following Code is accessing the selection in the CFileDialog
// and filling a string array with the selected names
BOOL CMyFileDialog::GetListControllSelectedItems(CStringArray& selectedItemNames)
{
BOOL rc = FALSE;
// Get the list control of the file dialog.
CWnd* pParentWnd = GetParent();
CWnd* pListControlWnd = pParentWnd->GetDlgItem(lst2);
if (pListControlWnd) {
// Get the selection from the list control.
CListCtrl* pListCtrl = (CListCtrl*)(pListControlWnd->GetDlgItem(1));
UINT selectionCount = pListCtrl->GetSelectedCount();
// When there are items selected.
if (selectionCount) {
rc = TRUE;
selectedItemNames.RemoveAll();
POSITION itemPos = pListCtrl->GetFirstSelectedItemPosition();
while (itemPos != NULL)
{
int itemNum = pListCtrl->GetNextSelectedItem(itemPos);
CString currentItemName = pListCtrl->GetItemText(itemNum, 0);
selectedItemNames.Add(currentItemName);
}
}
}
return rc;
}
注意:在CFileDialog::OnFileNameChange of the Microsoft MFC documentation 中,他们确实暗示了这个解决方案,但没有详细说明。
我的旧代码存在问题,我有一个自定义文件对话框,实际上需要保存一个文件夹!!!
经过二十二年的艰辛和痛苦,我的代码现在完成了……
【讨论】: