接受单个文件或单个目录的 QFileDialog
QFileDialog that accepts a single file or a single directory
是否可以显示一个QFileDialog,用户可以在其中选择文件或目录,无论是其中之一?
QFileDialog::getOpenFileName()
只接受文件,而QFileDialog::getExistingDirectory()
只接受目录,但我需要显示一个可以同时接受文件或目录的文件对话框(这对我的程序有意义)。 QFileDialog::Options
没有任何希望
QFileDialog 目前不支持此功能。我认为这里的主要问题是 FileMode 不是Q_FLAGS,值也不是 2 的幂,因此,您不能编写此内容来解决此问题。
setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles)
要解决这个问题,您需要相当多的摆弄,例如:
覆盖打开按钮单击操作。
正确获取文件和目录的"树视图"索引。
我在下面的尝试演示了前者,但我并没有真正解决第二个问题,因为这似乎涉及对选择模型的更多摆弄。
主.cpp
#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();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
构建和运行
qmake && make && ./main
相当老的问题,但我认为对于懒惰的人,我有一个比大多数更简单的解决方案。您可以将 QFileDialog 的信号电流更改与动态更改文件模式的函数连接。
//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);
});
}
然后简单地打电话给file_dialog。
if(file_dialog.exec()){
QStringList dir_names=file_dialog.selectedFiles():
}
对我有用的是使用:
file_dialog.setProxyModel(nullptr);
如此处的建议,或
class FileFilterProxyModel : public QSortFilterProxyModel
{
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel());
return (fileModel!=NULL && fileModel->isDir(sourceModel()->index(sourceRow, 0, sourceParent))) || QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
};
...
FileFilterProxyModel* proxyModel = new FileFilterProxyModel;
file_dialog.setProxyModel(proxyModel);
如此处的建议,或
class FileDialog : public QFileDialog
{
Q_OBJECT
public:
explicit FileDialog(QWidget *parent = Q_NULLPTR)
: QFileDialog(parent)
{
m_btnOpen = NULL;
m_listView = NULL;
m_treeView = NULL;
m_selectedFiles.clear();
this->setOption(QFileDialog::DontUseNativeDialog, true);
this->setFileMode(QFileDialog::Directory);
QList<QPushButton*> btns = this->findChildren<QPushButton*>();
for (int i = 0; i < btns.size(); ++i) {
QString text = btns[i]->text();
if (text.toLower().contains("open") || text.toLower().contains("choose"))
{
m_btnOpen = btns[i];
break;
}
}
if (!m_btnOpen) return;
m_btnOpen->installEventFilter(this);
//connect(m_btnOpen, SIGNAL(changed()), this, SLOT(btnChanged()))
m_btnOpen->disconnect(SIGNAL(clicked()));
connect(m_btnOpen, SIGNAL(clicked()), this, SLOT(chooseClicked()));
m_listView = findChild<QListView*>("listView");
if (m_listView)
m_listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_treeView = findChild<QTreeView*>();
if (m_treeView)
m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
QStringList selectedFiles()
{
return m_selectedFiles;
}
bool eventFilter( QObject* watched, QEvent* event )
{
QPushButton *btn = qobject_cast<QPushButton*>(watched);
if (btn)
{
if(event->type()==QEvent::EnabledChange) {
if (!btn->isEnabled())
btn->setEnabled(true);
}
}
return QWidget::eventFilter(watched, event);
}
public slots:
void chooseClicked()
{
QModelIndexList indexList = m_listView->selectionModel()->selectedIndexes();
foreach (QModelIndex index, indexList)
{
if (index.column()== 0)
m_selectedFiles.append(this->directory().absolutePath() + "/" + index.data().toString());
}
QDialog::accept();
}
private:
QListView *m_listView;
QTreeView *m_treeView;
QPushButton *m_btnOpen;
QStringList m_selectedFiles;
};
正如这里所建议的。感谢原作者和我。
连接到当前更改的信号,然后将文件模式设置为当前选定的项目(目录或文件)。这是一个 Python3 实现:
class GroupFileObjectDialog(QFileDialog):
def __init__(self, parent):
super().__init__(parent)
self.setOption(QFileDialog.DontUseNativeDialog)
self.setFileMode(QFileDialog.Directory)
self.currentChanged.connect(self._selected)
def _selected(self,name):
if os.path.isdir(name):
self.setFileMode(QFileDialog.Directory)
else:
self.setFileMode(QFileDialog.ExistingFile)
在运行在 Linux/Ubuntu18.04 上的 PyQt 5.14 上进行测试。
相关文章:
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- Eclipse CDT:单个项目中有多个C++文件
- 为什么我们将单个或多维数组的大小声明为常量值?
- C++调用具有 *this 属性的单个帮助程序函数
- 如何读取单个字符并在输入两个字符序列时输出? 使用 while 循环和C++
- 如何将可变参数模板转换为多个单个模板?(C++竞争编程调试模板)
- 将多个 for 循环组合成单个迭代器
- 如何将多种语言设置放在单个 .clang 格式文件中
- QT QOpenGLWidget:如何在不使用数据块复制的情况下修改VBO中的单个顶点值?
- 在 c++ 中对单个排序数组中的 2 个未排序数组进行排序
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- C++:如何用单个命令替换复杂的迭代?
- C++单个生成文件多个二进制文件
- 将单个未唱的 int 发送到 VBO
- 如何限制在C++中为单个类创建的对象数量?
- 为 QFileDialog 设置默认的 UNC 路径
- 在C++中使用线程查找友好号码比单个线程花费更多时间
- 从unordered_map中删除单个节点
- 接受单个文件或单个目录的 QFileDialog