如何将自定义项目添加到 QFileDialog?
Posted
技术标签:
【中文标题】如何将自定义项目添加到 QFileDialog?【英文标题】:How to add custom items to QFileDialog? 【发布时间】:2017-06-15 12:53:39 【问题描述】:我正在使用非本机 QFileDialog
(用于选择目录路径),我需要添加一些自定义驱动器。我现在什至不需要在这些驱动器中显示任何内容,我只需要在顶层显示这些驱动器(最好使用我的图标)并在用户选择它时在结果中输出一些特殊字符串。
最简单的实现方法是什么?
我在documentation 中读到代理模型可以用于此,但我不明白如何实现这样的模型,所有示例仅显示对已可用项目的过滤和排序。
【问题讨论】:
所以你想添加假驱动器?不幸的是,开箱即用的QFileDialog
不提供这种行为。一个选项是构建您自己的对话框并使用自定义 QFileSystemModel
是的。确定它不支持这个?文档说,“如果您想修改底层模型;例如,添加列、过滤数据或添加驱动器”,可以使用代理模型。
我可以看到如何过滤行,但添加行我不确定,抱歉
也许可以尝试编辑底层文件系统模型。
【参考方案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 有一个列表:FileIconRole
、FileNameRole
、FilePathRole
、FilePermissionRole
。
更糟糕的是,QFileDialog
sometimes calls proxyModel.mapToSource()
and proxyModel.mapFromSource()
访问源索引。因为我们要添加一行,所以我们的新索引没有对应的源索引(在源模型中)。这意味着我们必须编写自己的 mapToSource
和 mapFromSource
实现。
实施
我建议从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::data
和QAbstractItemModel::flags
。
结论
这应该是可行的,但工作量很大,很容易出错。 Qt 真正需要的似乎是将多个模型组合成一个的方法,但我还没有见过这样的类,因此你必须努力做到这一点。
【讨论】:
以上是关于如何将自定义项目添加到 QFileDialog?的主要内容,如果未能解决你的问题,请参考以下文章
如何将自定义密码编码器添加到 Spring Security?
如何将自定义标头从 mvc 项目发送到 Web api 项目?