【问题标题】:How to add custom items to QFileDialog?如何将自定义项目添加到 QFileDialog?
【发布时间】:2017-06-15 12:53:39
【问题描述】:

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

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

我在documentation 中读到代理模型可以用于此,但我不明白如何实现这样的模型,所有示例仅显示对已可用项目的过滤和排序。

【问题讨论】:

  • 所以你想添加假驱动器?不幸的是,开箱即用的QFileDialog 不提供这种行为。一个选项是构建您自己的对话框并使用自定义 QFileSystemModel
  • 是的。确定它不支持这个?文档说,“如果您想修改底层模型;例如,添加列、过滤数据或添加驱动器”,可以使用代理模型。
  • 我可以看到如何过滤行,但添加行我不确定,抱歉
  • 也许可以尝试编辑底层文件系统模型。

标签: c++ windows qt


【解决方案1】:

如果我理解正确,您想在文件对话框左侧的侧栏中添加其他驱动器吗?

你要找的函数是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();
}

这样的结果如下所示:

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

【讨论】:

  • 哦,我想这也是一个不错的选择,但是我实际上想将它添加到显示所有 Windows 驱动器的目录层次结构的顶层(也称为“我的电脑”)。它是仅限 Windows 的应用程序。为我的问题添加了屏幕截图。
【解决方案2】:

一般信息

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

如果我们查看QFileDialog::setProxyModel的源代码,我们会发现:

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

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

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

实施

我建议从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 真正需要的似乎是将多个模型组合成一个的方法,但我还没有见过这样的类,因此你必须努力做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多