C++选择文件夹,包括文件

C++ Select Folder, Include Files

本文关键字:包括 文件 文件夹 选择 C++      更新时间:2023-10-16

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

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

我错过了任何选择吗?似乎显示文件而不允许用户选择它们的IFileOpenDialog将是理想的。有什么办法可以做到这一点吗?我发现很多较早的信息说这是不可能的,但没有确定的,这是最近的。

您是否尝试过QML文件对话框FileDialogselectFolder: true?由于 Qt5 文档说

如果可能,FileDialog 的实现将是一个平台文件对话框。如果这是不可能的,那么它将尝试实例化QFileDialog。

对于目录集,它可能更用户友好,因为它使用比 QFileDialog 更多的本机对话框。我在MacOS上尝试过,它可以完美地显示您想要的行为,但是我附近没有Windows开发机器,但是找到了一个最小的项目:

main.qml:

import QtQuick 2.2
import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.2
ApplicationWindow
{
visible: true
width: 640
height: 480
title: qsTr("Minimal Qml")
FileDialog {
id: fileDialog
title: "Please choose a directory"
selectFolder: true
folder: shortcuts.home
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
Qt.quit()
}
onRejected: {
console.log("Canceled")
Qt.quit()
}
Component.onCompleted: visible = true
}
}   

主.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("main.qml")));
return app.exec();
}

qml.qrc

<RCC>
<qresource prefix="⁄">
<file>main.qml</file>
</qresource>
</RCC>

CMakeList.txt

cmake_minimum_required(VERSION 3.13)
project(untitled1)
set(CMAKE_CXX_STANDARD 14)
find_package(Qt5 COMPONENTS Widgets Qml Quick REQUIRED)

include_directories(${Qt5Widgets_INCLUDE_DIRS} ${QtQml_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS} ${QtQml_DEFINITIONS} ${${Qt5Quick_DEFINITIONS}})
qt5_add_resources(QT_RESOURCES qml.qrc)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(PROJECT "MinimalQml")
configure_file(main.qml main.qml COPYONLY)
add_executable(${PROJECT} main.cpp ${QT_RESOURCES})
target_link_libraries(${PROJECT}
Qt5::Widgets
Qt5::Qml
Qt5::Quick
)

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

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

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

这里快速比较了两种选择目录的方法,使用QFileDialog::getExistingDirectory、手动创建QFileDialog实例和使用本机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;
}

尽管有SHBrowseForFolder错误,但我 100% 更喜欢它,因为当临时用户看到的只是一个空白区域时,他肯定会对 IFileOpenDialog 感到困惑。甚至我自己偶尔也会感到困惑。编写代码也更简单。

我总是BIF_EDITBOX使用它,以允许高级用户快速键入路径,而且,我总是在另一个具有预选路径和"更改文件夹"按钮的对话框中使用它。