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));
  }
}
posted @ 2025-05-14 21:09  卑以自牧lq  阅读(7)  评论(0)    收藏  举报