QFileDialog, который принимает один файл или один каталог

98
10

Можно ли показать QFileDialog, где пользователь может выбрать файл или каталог, либо один?


QFileDialog::getOpenFileName() принимает только файлы, а QFileDialog::getExistingDirectory() - только для каталогов, но мне нужно показать диалоговое окно файла, которое может принимать как файл, так и каталог (это имеет смысл для моей программы). QFileDialog::​Options не было ничего обещающего.

спросил(а) 2014-12-17T10:29:00+03:00 5 лет, 9 месяцев назад
1
Решение
89

QFileDialog в настоящее время не поддерживает это. Я думаю, что основная проблема для вас здесь заключается в том, что FileMode не является Q_FLAGS, и значения не равны 2, и поэтому вы не можете написать это, чтобы решить эту проблему.


setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles)

Чтобы решить эту проблему, вам потребуется довольно много возиться, например:


    Отмените операцию нажатия кнопки открытия.


    Получить "древовидные" индексы должным образом для файлов и каталогов.


Моя попытка ниже демонстрирует первое, но я действительно не зашел так далеко, как решает второй, потому что это, по-видимому, связано с еще более возиться с моделью выбора.


main.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

ответил(а) 2014-12-17T12:22:00+03:00 5 лет, 9 месяцев назад
57

Что сработало для меня было:


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;
};


как предложено здесь. Кредиты для оригинальных авторов и меня.

ответил(а) 2018-01-09T23:29:00+03:00 2 года, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема