openFileDialog
open File dialog
方案一:
QDialog,会根据输入自动匹配
#include <QFileDialog>
#include <QFileSystemModel>
#include <QKeyEvent>
#include <QLineEdit>
#include <QSortFilterProxyModel>
class FileNameFilterHelper : public QObject {
Q_OBJECT
public:
FileNameFilterHelper(QFileDialog* dlg, const QString& suf) : m_dialog(dlg), m_suffix(suf) {}
public slots:
void onTextChanged(const QString& text) {
if (!m_dialog) return;
QString pattern = QString("*%1*").arg(text.trimmed());
if (patern.size() < 15) {
pattern += ";;" + m_suffix;
m_dialog->setNameFilter(pattern);
}
}
private:
QFileDialog* m_dialog;
QString m_suffix;
};
class skiOpenForm : public QWidget {
Q_OBJECT
public:
void onFileBrowse(const QString& dir /* = "" */);
private:
};
void skiOpenForm::onFileBrowse(const QString& dir /* = "" */) {
QString suffix =
"All (*);;"
"Supported (*.gds *.oas *.gz *.GDS *.OAS *.GZ);;"
"GDS (*.gds *.GDS);;"
"OASIS (*.oas *.OAS);;"
"Compressed (*.gz *.GZ)";
QFileDialog dialog(this, tr("Open"), dir, suffix);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
QLineEdit* lineEdit = dialog.findChild<QLineEdit*>("fileNameEdit");
if (lineEdit) {
// 创建中介对象
FileNameFilterHelper* filterHelper = new FileNameFilterHelper(&dialog);
QObject::connect(lineEdit, SIGNAL(textChanged(const QString&)),
filterHelper, SLOT(onTextChanged(const QString&)));
}
QString fileStr;
if (dialog.exec() == QDialog::Accepted) {
QStringList fileNames = dialog.selectedFiles();
for (int i = 0; i < fileNames.size(); ++i) {
fileStr += fileNames[i];
if (i != fileNames.size() - 1) fileStr += ";";
}
if (!fileStr.isEmpty()) {
// m_fileLE->setText(fileStr);
}
}
}
方案二:用户按回车键再匹配
#include <QFileDialog>
#include <QFileSystemModel>
#include <QKeyEvent>
#include <QLineEdit>
#include <QSortFilterProxyModel>
class EnterKeyFilter : public QObject {
Q_OBJECT
public:
EnterKeyFilter(QFileDialog* dialog, QLineEdit* edit, const QString& suf)
: QObject(dialog), m_dialog(dialog), m_edit(edit), m_suf(suf) {}
protected:
bool eventFilter(QObject* obj, QEvent* event) {
if (obj == m_edit && event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Enter) {
QString text = m_edit->text().trimmed();
// 判断是否含有通配符
if (text.contains("*") || text.contains("?")) {
text += ";;" + m_suf;
m_dialog->setNameFilter(text);
// 拦截回车,不让 QFileDialog 执行默认“选择文件并关闭窗口”操作
return true;
}
}
}
// 默认行为不拦截
return QObject::eventFilter(obj, event);
}
private:
QFileDialog* m_dialog;
QLineEdit* m_edit;
QString m_suf;
};
class skiOpenForm : public QWidget {
Q_OBJECT
public:
void onFileBrowse(const QString& dir /* = "" */);
private:
};
void skiOpenForm::onFileBrowse(const QString& dir /* = "" */) {
QString suffix =
"All (*);;"
"Supported (*.gds *.oas *.gz *.GDS *.OAS *.GZ);;"
"GDS (*.gds *.GDS);;"
"OASIS (*.oas *.OAS);;"
"Compressed (*.gz *.GZ)";
QFileDialog dialog(this, tr("Open"), dir, suffix);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
QLineEdit* lineEdit = dialog.findChild<QLineEdit*>("fileNameEdit");
if (lineEdit) {
EnterKeyFilter* enterFilter = new EnterKeyFilter(&dialog, lineEdit, suffix);
lineEdit->installEventFilter(enterFilter);
}
QString fileStr;
if (dialog.exec() == QDialog::Accepted) {
QStringList fileNames = dialog.selectedFiles();
for (int i = 0; i < fileNames.size(); ++i) {
fileStr += fileNames[i];
if (i != fileNames.size() - 1) fileStr += ";";
}
if (!fileStr.isEmpty()) {
// m_fileLE->setText(fileStr);
}
}
}
方案三 更优方案,双重过滤
头文件:
class skiFileFilterProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
explicit skiFileFilterProxyModel(QObject* parent, QLineEdit* le) :
QSortFilterProxyModel(parent),
m_edit(le),
m_inputReg(QRegExp(".*", Qt::CaseSensitive)) {}
void setExtensionFilterPattern(const QString& pattern);
private slots:
void onFilterChanged(const QString& filter);
private:
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const;
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
bool eventFilter(QObject* obj, QEvent* event);
private:
QLineEdit* m_edit;
QRegExp m_inputReg;
vector<QRegExp> m_selectedRegs;
};
class skiOpenForm : public QWidget {
Q_OBJECT
public:
void onFileBrowse(const QString& dir /* = "" */);
};
QString suffix = "All (*);;"
"Supported (*.gds *.oas *.gz *.GDS *.OAS *.GZ);;"
"GDS (*.gds *.GDS);;"
"OASIS (*.oas *.OAS);;"
"Compressed (*.gz *.GZ)";
void
skiOpenForm::onFileBrowse(const QString &dir) {
QFileDialog dialog(this, tr("Open"), dir, suffix);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
QFileSystemModel *fsm = new QFileSystemModel(&dialog);
fsm->setRootPath(dir);
QLineEdit *fileNameEdit = dialog.findChild<QLineEdit *>("fileNameEdit");
skiFileFilterProxyModel *proxy = new skiFileFilterProxyModel(&dialog, fileNameEdit);
proxy->setSourceModel(fsm);
dialog.setProxyModel(proxy);
QRegExp re("\\(([^\\)]+)\\)");
if (re.indexIn(dialog.selectedNameFilter()) != -1)
proxy->setExtensionFilterPattern(re.cap(1));
connect(&dialog, SIGNAL(filterSelected(const QString &)), proxy,
SLOT(onFilterChanged(const QString &)));
if (fileNameEdit) {
fileNameEdit->installEventFilter(proxy);
}
QTreeView *tree = dialog.findChild<QTreeView *>();
if (tree) {
tree->setSortingEnabled(true);
tree->sortByColumn(0, Qt::AscendingOrder);
}
QString fileStr;
if (dialog.exec() == QDialog::Accepted) {
QStringList fileNames = dialog.selectedFiles();
for (int i = 0; i < fileNames.size(); ++i) {
fileStr += fileNames[i];
if (i != fileNames.size() - 1) fileStr += ";";
}
if (!fileStr.isEmpty()) {
printf("file: %s\n", fileStr.toStdString().c_str());
}
}
}
bool
skiFileFilterProxyModel::eventFilter(QObject *obj, QEvent *event) {
if (obj == m_edit && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
QString text = m_edit->text();
if (text.size() == 0) {
m_inputReg = QRegExp(".*", Qt::CaseSensitive);
invalidate();
return true;
}
if (text.size() < 30 && (text.contains("*") || text.contains("?"))) {
m_inputReg = QRegExp(QRegExp::escape(text).replace("\\*", ".*").replace("\\?", "."), Qt::CaseSensitive);
invalidate();
return true;
}
}
}
return QObject::eventFilter(obj, event);
}
void
skiFileFilterProxyModel::onFilterChanged(const QString &filter) {
QRegExp re("\\(([^\\)]+)\\)");
if (re.indexIn(filter) != -1)
setExtensionFilterPattern(re.cap(1));
else
setExtensionFilterPattern("*");
invalidate();
}
bool
skiFileFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
QString fileName = sourceModel()->data(index, Qt::DisplayRole).toString();
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(this->sourceModel());
if (fsm) {
QFileInfo fileInfo = fsm->fileInfo(index);
if (fileInfo.isDir())
return true; // Always accept folders
}
bool extMatch = false;
for (const QRegExp& rx : m_selectedRegs) {
if (rx.exactMatch(fileName)) {
extMatch = true;
break;
}
}
return extMatch && m_inputReg.exactMatch(fileName);
}
bool
skiFileFilterProxyModel::lessThan(const QModelIndex &left,
const QModelIndex &right) const {
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
if (!fsm)
return QSortFilterProxyModel::lessThan(left, right);
QFileInfo leftInfo = fsm->fileInfo(left);
QFileInfo rightInfo = fsm->fileInfo(right);
bool leftIsDir = leftInfo.isDir();
bool rightIsDir = rightInfo.isDir();
if (leftIsDir && !rightIsDir)
return true;
if (!leftIsDir && rightIsDir)
return false;
return QString::localeAwareCompare(leftInfo.fileName(), rightInfo.fileName()) < 0;
}
void skiFileFilterProxyModel::setExtensionFilterPattern(const QString &pattern) {
m_selectedRegs.clear();
QStringList patterns = pattern.split(' ', QString::SkipEmptyParts);
for (const QString &p : patterns) {
m_selectedRegs.emplace_back(QRegExp(QRegExp::escape(p).replace("\\*", ".*").replace("\\?", "."), Qt::CaseSensitive));
}
}