如何将自定义项目添加到QFileDialog?

我正在使用非本地QFileDialog (用于选择目录路径),我需要添加一些自定义驱动器。 我甚至不需要在这些驱动器中显示任何内容,我只需要在顶层显示这些驱动器(最好是使用我的图标),并在用户选择它时在结果中输出一些特殊的字符串。

在这里输入图像描述

实现这个最简单的方法是什么?

我已经阅读过可以使用代理模型的文档,但我不明白如何实现这种模型,所有示例仅显示对已有项目进行过滤和排序。


如果我理解正确,你想添加额外的驱动器到文件对话框左侧的侧栏上?

你正在寻找的功能是QFileDialog::setSidebarUrls

#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileDialog>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    QMainWindow window;

    QWidget widget;
    QHBoxLayout layout(&widget);

    QPushButton open("open");
    layout.addWidget(&open);

    QObject::connect(&open, &QPushButton::clicked, [&]()
        {
            QFileDialog dialog;
            dialog.setOption(QFileDialog::DontUseNativeDialog);

            QList<QUrl> drives;
            drives << QUrl::fromLocalFile(QDir("D:").absolutePath());
            drives << QUrl::fromLocalFile(QDir("E:").absolutePath());
            drives << QUrl::fromLocalFile(QDir("foobar").absolutePath());
            dialog.setSidebarUrls(drives);

            dialog.exec();
        });

    window.setCentralWidget(&widget);
    window.show();
    return app.exec();
}

结果如下所示:

在这里输入图像描述

但是,如果您添加的驱动器不存在/无法访问,则它们将显示为灰色。


一般信息

你是对的,你需要设置一个代理模型。 基本上你的任务是用QAbstractProxyModel添加一行。 这比删除行要困难得多。

如果我们看一下QFileDialog::setProxyModel的源代码,我们发现这个:

proxyModel->setParent(this);
d->proxyModel = proxyModel;
proxyModel->setSourceModel(d->model);

由此我们知道QFileDialog有一个自动设置为代理模型源的内部模型。 查看私有头文件,我们发现源模型的类型是QFileSystemModel 。 因此,我们可以期望我们的代理模型需要能够提供与源模型相同的角色。 该文档具有它们的列表: FileIconRoleFileNameRoleFilePathRoleFilePermissionRole

更糟糕的是, QFileDialog有时会调用proxyModel.mapToSource()proxyModel.mapFromSource()来访问源索引。 因为我们要添加一行,所以我们的新索引没有相应的源索引(在源模型中)。 这意味着我们必须编写我们自己的mapToSourcemapFromSource的实现。

履行

我建议从QIdentityProxyModel开始,因为你可以使用可用的方法来处理所有刚刚传递给源模型的索引。

我不清楚你需要重新实现多少种方法,以及你可以多久使用QIdentityProxyModel提供的QIdentityProxyModel 。 从简单的东西开始:

int MyDriveProxyModel::rowCount(const QModelIndex &parent = QModelIndex()) const {
    if (parent.isValid()) {
        return QIdentityProxyModel::rowCount(parent);
    } else {
        return QIdentityProxyModel::rowCount(parent) + 1;
    }
}

然后重新实现两种映射方法:

QModelIndex MyDriveProxyModel::mapToSource(const QModelIndex &proxyIndex) const {
    if (this_index_belongs_to_the_added_row) { // there are many ways for this
        return this->createIndex(proxyIndex.row(), proxyIndex.column(), /* some_data */);
    }
    return QIdentityProxyModel::mapToSource(proxyIndex);
}

QModelIndex MyDriveProxyModel::mapFromSource(const QModelIndex &proxyIndex) const {
    ...
}

一旦这个工作,你需要以类似的方式至少实现QAbstractItemModel::dataQAbstractItemModel::flags

结论

它应该是可行的,但是在犯错误很容易的地方是相当多的工作。 Qt真正需要的是一种将多个模型合并为一个的方法,但我还没有看到过这样的类,因此您必须这样做。

链接地址: http://www.djcxy.com/p/96515.html

上一篇: How to add custom items to QFileDialog?

下一篇: How to launch and open email client React