【问题标题】:CFileDialog :: Browse foldersCFileDialog :: 浏览文件夹
【发布时间】:2010-11-21 05:53:26
【问题描述】:

当我尝试实例化 CFileDialog 对象时,它会同时显示文件夹和文件。你如何创建一个单独浏览文件夹的CFileDialog

【问题讨论】:

    标签: mfc visual-c++


    【解决方案1】:

    真的很简单。

    使用派生自类CFileDialogCFolderPickerDialog

    【讨论】:

    • 这个类从 Visual Studio 2010 开始存在。我们刚刚从 VS2008 切换到 VS2013,IFileOpenDialog::SetOptions(FOS_PICKFOLDERS) 出人意料地停止了工作。恕我直言,这是违反向后兼容性的。
    【解决方案2】:

    CFileDialog 无法做到这一点。

    您将使用SHBrowseForFolder Function 或包装器,
    CFolderDialog - Selecting Folders.

    【讨论】:

    • SHBrowseForFolder 已经严重过时了。来自备注:“对于 Windows Vista 或更高版本,建议您使用 IFileDialog 和 FOS_PICKFOLDERS 选项而不是 SHBrowseForFolder 函数。这使用选择文件夹模式下的打开文件对话框,是首选实现。”我>
    • 如果您愿意重新实现CFileDialog,实际上可以 - 请参阅here
    • @Juv,问题是关于在对话框中只显示文件夹。
    【解决方案3】:

    从 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();
    

    【讨论】:

    【解决方案4】:

    就像有人提到的那样,使用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);
    
            }
        }
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        在我看来,您要的答案在

        的代码中
        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

        【讨论】:

          【解决方案7】:

          其实有办法做到这一点——我在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 中,他们确实暗示了这个解决方案,但没有详细说明。

          我的旧代码存在问题,我有一个自定义文件对话框,实际上需要保存一个文件夹!!!

          经过二十二年的艰辛和痛苦,我的代码现在完成了……

          【讨论】:

            猜你喜欢
            • 2013-02-01
            • 1970-01-01
            • 2020-12-31
            • 1970-01-01
            • 1970-01-01
            • 2011-05-27
            • 2018-09-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多