限制用户在 QFileDialog 中可以 select 的文件数量

Limit amount of files user can select in QFileDialog

这里是代码:

dialog = new QFileDialog(this);
dialog->setFileMode(QFileDialog::ExistingFiles);
connect(dialog, SIGNAL(currentChanged(const QString&)),
    this, SLOT(dialogSelectionChanged(const QString&)));

void MainWindow::dialogSelectionChanged(const QString& file)
{
    QStringList selected = dialog->selectedFiles();
}

问题是

这就是我不知道如何跟踪当前选定文件的原因。 另一个问题是,如果用户超过允许的选择限制,我目前还不知道如何取消选择最后选择的文件。

我见过几个示例,其中人们使用 QProxyModelQFileDialog 的自定义实现来实现自定义功能,但我不确定哪种方式最适合我的需求。

没有方法可以做到这一点,但是一旦您的客户完成选择,您就可以通过调用方法 selectedFiles

来验证操作

QStringList 的大小是否大于您的约束,您可以中止操作并显示一些错误消息。

喜欢

void MainWindow::dialogSelectionChanged(const QString& file)
{
    QStringList selected = dialog->selectedFiles();
    if(selected.size()>LIMIT)
    {
        showErrorMsg("some helpful mesage");
    }

}

如果你愿意接受无耻的黑客攻击,这是可以做到的:-)

假设以下代码...

QFileDialog fd;

使用 fd.findChildren<QListView *>() 检查 fd 显示它有两个 children 是或继承自 QListView...

  1. 名为 listView 的 QListView
  2. QSidebar 名为侧边栏

(其中 QSidebar 是 Qt 私有的)。

假定名为 listViewQListView 是您感兴趣的小部件,您可以将回调连接到其选择模型...

QFileDialog fd;
for (const auto &i: fd.findChildren<QListView *>("listView")) {
  auto *sm = i->selectionModel();
  QObject::connect(sm, &QItemSelectionModel::selectionChanged,
                   [sm](const QItemSelection &selected, const QItemSelection &deselected)
                     {

                       /*
                        * Here we pass a hard-coded max selected items
                        * value of 5 to the real callback/slot.
                        */
                       handle_selection_updated(5, sm, selected, deselected);
                     });
}

这里handle_selection_updated有如下定义...

void handle_selection_updated (int selection_max, QItemSelectionModel *sm,
                               const QItemSelection &selected,
                               const QItemSelection &deselected)
{

  /*
   * We need to remember the last valid selection.  The following
   * is declared static in this simple case but would generally be
   * a class member in `real' code.
   */
  static QItemSelection last_selected;

  /*
   * Because we update the selection model `sm' from within this
   * slot this function will recurse which will cause problems if
   * we don't detect it and take appropriate action.
   */
  static bool recursing = false;
  if (recursing)
    return;

  /*
   * If the number of rows selected is greater than the value
   * specified by `selection_max' then revert to the last valid
   * selection as specified by `last_selected'.
   */
  if (sm->selectedRows().size() > selection_max) {

    /*
     * The following call to QItemSelectionModel::clearSelection
     * will result in a recursive call to this function.  Set
     * `recursing' to true to catch this and avoid associated
     * problems.
     */
    recursing = true;

    /*
     * Now clear the selection and reset it to the items from
     * `last_selected'.
     */
    sm->clearSelection();
    for (const auto &i: last_selected.indexes()) {
      sm->select(i, QItemSelectionModel::Select);
    }
    recursing = false;
  }

  /*
   * Update `last_selected'.
   */
  last_selected = sm->selection();
}

我只简单地测试了上面的代码,但它的行为似乎符合要求。