接受单个文件或单个目录的QFileDialog

sas*_*alm 7 c++ qt qfiledialog

是否可以显示QFileDialog,用户可以在其中选择一个文件或目录?

QFileDialog::getOpenFileName()只接受文件,而QFileDialog::getExistingDirectory()只是目录,但我需要显示一个文件对话框,可以接受文件或目录(这对我的程序有意义).QFileDialog::?Options没有什么有希望的.

lpa*_*app 7

QFileDialog 目前不支持这个。我认为这里的主要问题是FileMode不是Q_FLAGS并且值也不是 2 的幂,因此,您无法编写它来解决此问题。

setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles)
Run Code Online (Sandbox Code Playgroud)

要解决此问题,您需要进行大量操作,例如:

  • 覆盖打开按钮的点击操作。

  • 正确获取文件和目录的“树视图”索引。

我在下面的尝试演示了前者,但我并没有真正解决第二个问题,因为这似乎涉及更多地摆弄选择模型。

主程序

#include <QFileDialog>
#include <QApplication>
#include <QWidget>
#include <QTreeWidget>
#include <QPushButton>
#include <QStringList>
#include <QModelIndex>
#include <QDir>
#include <QDebug>

class FileDialog : public QFileDialog
{
    Q_OBJECT
    public:
        explicit FileDialog(QWidget *parent = Q_NULLPTR)
            : QFileDialog(parent)
        {
            setOption(QFileDialog::DontUseNativeDialog);
            setFileMode(QFileDialog::Directory);
            // setFileMode(QFileDialog::ExistingFiles);
            for (auto *pushButton : findChildren<QPushButton*>()) {
                qDebug() << pushButton->text();
                if (pushButton->text() == "&Open" || pushButton->text() == "&Choose") {
                    openButton = pushButton;
                    break;
                }
            }
            disconnect(openButton, SIGNAL(clicked(bool)));
            connect(openButton, &QPushButton::clicked, this, &FileDialog::openClicked);
            treeView = findChild<QTreeView*>();
        }

        QStringList selected() const
        {
            return selectedFilePaths;
        }

    public slots:
        void openClicked()
        {
            selectedFilePaths.clear();
            qDebug() << treeView->selectionModel()->selection();
            for (const auto& modelIndex : treeView->selectionModel()->selectedIndexes()) {
                qDebug() << modelIndex.column();
                if (modelIndex.column() == 0)
                    selectedFilePaths.append(directory().absolutePath() + modelIndex.data().toString());
            }
            emit filesSelected(selectedFilePaths);
            hide();
            qDebug() << selectedFilePaths;
       }

    private:
        QTreeView *treeView;
        QPushButton *openButton;
        QStringList selectedFilePaths;
};

#include "main.moc"

int main(int argc, char **argv)
{
    QApplication application(argc, argv);
    FileDialog fileDialog;
    fileDialog.show();
    return application.exec();
}
Run Code Online (Sandbox Code Playgroud)

主程序

TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
Run Code Online (Sandbox Code Playgroud)

构建和运行

qmake && make && ./main
Run Code Online (Sandbox Code Playgroud)


Spy*_*tos 5

这是一个很老的问题,但我认为对于懒惰的人来说,我有一个比大多数更简单的解决方案。您可以将 QFileDialog 的信号 currentChanged 与动态更改 fileMode 的函数连接起来。

//header
class my_main_win:public QMainWindow  
{
private:
    QFileDialog file_dialog;    
}

//constructor 

my_main_win(QWidget * parent):QMainWindow(parent)
{
    connect(&file_dialog,QFileDialog::currentChanged,this,[&](const QString & str)
        {
        QFileInfo info(str);
        if(info.isFile())
            file_dialog.setFileMode(QFileDialog::ExistingFile);
        else if(info.isDir())
            file_dialog.setFileMode(QFileDialog::Directory);
    });
}
Run Code Online (Sandbox Code Playgroud)

然后简单地调用 file_dialog 即可。

if(file_dialog.exec()){
    QStringList dir_names=file_dialog.selectedFiles():
}
Run Code Online (Sandbox Code Playgroud)