有没有可能显示一个QFileDialog,用户可以在其中选择一个文件或一个目录?QFileDialog::getOpenFileName()只接受文件,而QFileDialog::getExistingDirectory()只接受目录,但我需要显示一个文件对话框,它既可以接受文件,也可以接受目录(这对我的程序很有意义)。
QFileDialog::getOpenFileName()
QFileDialog::getExistingDirectory()
hc2pp10m1#
QFileDialog目前不支持这个功能,我认为这里的主要问题是FileMode不是Q_FLAGS,值也不是2的幂,所以,你不能写这个来解决这个问题。
setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles)
要解决这个问题,你需要相当多的摆弄,例如:
我下面的尝试演示了前者,但我并没有真正解决第二个问题,因为这似乎涉及到更多的选择模型的摆弄。
#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(); }
TEMPLATE = app TARGET = main QT += widgets CONFIG += c++11 SOURCES += main.cpp
qmake && make && ./main
aiqt4smr2#
很老的问题,但是我想我有一个比大多数懒惰的人更简单的解决方案。你可以把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); }); }
然后简单地调用file_dialog。
if(file_dialog.exec()){ QStringList dir_names=file_dialog.selectedFiles(): }
14ifxucb3#
对我有效的方法是用途:
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);
如建议here,或
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; };
正如这里所建议的。原作者和我的学分。
r55awzrz4#
连接currentChanged信号,然后将文件模式设置为当前选定的项(目录或文件)。
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 /Ubuntu 18.04上运行的PyQt 5.14上进行了测试。
4条答案
按热度按时间hc2pp10m1#
QFileDialog目前不支持这个功能,我认为这里的主要问题是FileMode不是Q_FLAGS,值也不是2的幂,所以,你不能写这个来解决这个问题。
要解决这个问题,你需要相当多的摆弄,例如:
我下面的尝试演示了前者,但我并没有真正解决第二个问题,因为这似乎涉及到更多的选择模型的摆弄。
主文件. cpp
main.pro
构建和运行
aiqt4smr2#
很老的问题,但是我想我有一个比大多数懒惰的人更简单的解决方案。你可以把QFileDialog的currentChanged信号和一个动态改变fileMode的函数连接起来。
然后简单地调用file_dialog。
14ifxucb3#
对我有效的方法是用途:
如此处所述,或
如建议here,或
正如这里所建议的。原作者和我的学分。
r55awzrz4#
连接currentChanged信号,然后将文件模式设置为当前选定的项(目录或文件)。
在Linux /Ubuntu 18.04上运行的PyQt 5.14上进行了测试。