首页 > 解决方案 > C++ 选择文件夹,包含文件

问题描述

我目前正在为 Windows 开发一个 qt 应用程序。用户需要能够选择一个目录来加载所有文件。我有一个与此相关的问题。这似乎很愚蠢,但我一直得到相同的反馈。最终用户对文件对话框感到困惑,因为他们导航到该文件夹​​,但它不显示任何文件。即使他们正在选择一个文件夹,这也会让他们感到困惑,因为他们看不到目录中的文件。

所以我决定深入研究它并做一些研究。从我发现的情况来看,似乎基本上有两种选择。IFileOpenDialogwith ,这FOS_PICKFOLDERS是我目前通过 qt's 使用的QFileDialog。或者SHBrowseForFolder,它确实有效,但非常有限。

我错过了任何选择吗?似乎IFileOpenDialog在不允许用户选择文件的情况下显示文件是理想的。有没有办法做到这一点?我发现很多旧信息都说这是不可能的,但没有任何确定的信息是最近的。

标签: c++windowsqtwinapi

解决方案


主要问题是,如文档中所述,Windows 的本机文件对话框不支持仅在选择目录时同时显示文件和目录(也请查看其他相关答案)。对于QFileDialog::FileMode::Directory

目录的名称。显示文件和目录。但是,本机 Windows 文件对话框不支持在目录选择器中显示文件。

一种解决方法是使用非本机文件对话框进行这种选择,但就个人而言,如果它必须与其他本机文件对话框一起使用,它看起来很糟糕。

这里快速比较了两种选择目录的方法,使用QFileDialog::getExistingDirectory、手动创建实例QFileDialog和使用 native IFileDialog

#include <qapplication.h>
#include <qfiledialog.h>
#include <qdebug.h>
#include <Windows.h>
#include <shobjidl.h>

void using_IFileDialog()
{
  IFileOpenDialog* pFileOpen;
  HRESULT hr;

  // Create the FileOpenDialog object.
  hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
                        IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));

  if (SUCCEEDED(hr)) {
    // Show the Open dialog box.
    pFileOpen->SetOptions(FOS_PICKFOLDERS | FOS_PATHMUSTEXIST);
    hr = pFileOpen->Show(NULL);

    // Get the file name from the dialog box.
    if (SUCCEEDED(hr)) {
      IShellItem* pItem;
      hr = pFileOpen->GetResult(&pItem);
      if (SUCCEEDED(hr)) {
        PWSTR pszFilePath;
        hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);

        // Display the file name to the user.
        if (SUCCEEDED(hr)) {
          MessageBox(NULL, pszFilePath, L"File Path", MB_OK);
          CoTaskMemFree(pszFilePath);
        }
        pItem->Release();
      }
    }
    pFileOpen->Release();
  }
}

int main(int argc, char* argv[])
{
  QApplication a(argc, argv);

  const auto dir_1 = QFileDialog::getExistingDirectory(nullptr, "getExistingDirectory (dirs only)");
  qDebug() << dir_1;

  QFileDialog dlg(nullptr, "QFileDialog::DontUseNativeDialog");
  dlg.setFileMode(QFileDialog::Directory);
  dlg.setOption(QFileDialog::DontUseNativeDialog);
  if (dlg.exec() == QFileDialog::Accepted) {
    const auto dir_2 = dlg.directory().absolutePath();
    qDebug() << dir_2;
  }

  using_IFileDialog();

  return 0;
}

推荐阅读