【问题标题】:Qt: Multiple QListWidgets and only a single entry selectedQt:多个 QListWidgets 并且只选择了一个条目
【发布时间】:2018-01-12 13:13:57
【问题描述】:

我有几个QListWidgets,并且希望只允许为所有这些列表选择一行。因此,例如,如果我在其中一个列表中选择一行,则其他列表中的任何其他选择都将被清除。我怎样才能做到这一点?

有没有内置的方法来做到这一点(类似于按钮的 QButtonGroup)?如果不是,您会建议我在尝试自己实施时采用什么方法?

感谢您的帮助和亲切的问候, 托德

【问题讨论】:

  • 为每个列表小部件编写一个信号处理程序,取消选择所有其他列表小部件。 AFAIK,没有现成的内置功能。 (您可能要小心:取消选择也可能触发相应的选择信号。因此,您应该考虑对递归进行某种锁定。)

标签: qt pyqt qt5 pyqt5 qlistwidget


【解决方案1】:

AFAIK,没有现成的内置功能可以在多个列表视图中提供单个选择。

相反,它可以由QSelectionModel::selectionChanged 信号的相应信号处理程序完成,只要涉及的列表视图之一的选择发生变化,就会执行此操作。

因此,您必须考虑清除选择也会发出selectionChanged 信号。 (否则,您可能会递归调用信号处理程序,直到发生堆栈溢出。)

不幸的是,我在 C++ 中使用 Qt。 (我的 Python 知识相当有限。)

因此,我现在所能提供的只是我在 C++ 中的“概念证明”:

#include <QtWidgets>

void singleSel(QListView *pLstView, const QList<QListView*> &pLstViews)
{
  for (QListView *pLstViewI : pLstViews) {
    if (pLstViewI == pLstView) continue; // skip sender
    // the check is necessary to prevent recursions...
    if (pLstView->selectionModel()->hasSelection()) {
      // ...as this causes emission of selectionChanged() signal as well:
      pLstViewI->selectionModel()->clearSelection();
    }
  }
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version: " << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build contents
  QStandardItemModel tblModel(0, 1);
  for (int i = 0; i < 10; ++i) {
    tblModel.appendRow(
      new QStandardItem(QString::fromUtf8("Entry %0").arg(i + 1)));
  }
  // build some GUI
  QWidget win;
  QHBoxLayout qHBox;
  QListView lstView1;
  lstView1.setModel(&tblModel);
  qHBox.addWidget(&lstView1);
  QListView lstView2;
  lstView2.setModel(&tblModel);
  qHBox.addWidget(&lstView2);
  QListView lstView3;
  lstView3.setModel(&tblModel);
  qHBox.addWidget(&lstView3);
  win.setLayout(&qHBox);
  win.show();
  // install signal handlers
  QList<QListView*> pLstViews = { &lstView1, &lstView2, &lstView3 };
  QObject::connect(lstView1.selectionModel(),
    &QItemSelectionModel::selectionChanged,
    [&lstView1, &pLstViews](const QItemSelection&, const QItemSelection &)
    {
      singleSel(&lstView1, pLstViews);
    });
  QObject::connect(lstView2.selectionModel(),
    &QItemSelectionModel::selectionChanged,
    [&lstView2, &pLstViews](const QItemSelection&, const QItemSelection &)
    {
      singleSel(&lstView2, pLstViews);
    });
  QObject::connect(lstView3.selectionModel(),
    &QItemSelectionModel::selectionChanged,
    [&lstView3, &pLstViews](const QItemSelection&, const QItemSelection &)
    {
      singleSel(&lstView3, pLstViews);
    });
  // exec. application
  return app.exec();
}

我在 Windows 10(64 位)上编译和测试。看起来是这样的:


更新:

我尝试将 C++ 应用程序移植到 Python/PyQt5:

#!/usr/bin/python3

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QListView
from PyQt5.QtGui import QStandardItemModel, QStandardItem

def singleSelect(lstView, lstViews):
  for lstViewI in lstViews:
    if lstViewI == lstView:
      continue
    # the check is necessary to prevent recursions...
    if lstViewI.selectionModel().hasSelection():
      # ...as this causes emission of selectionChanged() signal as well:
      lstViewI.selectionModel().clearSelection()

if __name__ == '__main__':
  app = QApplication(sys.argv)
  # build contents
  tblModel = QStandardItemModel(0, 1)
  for i in range(0, 10):
    tblModel.appendRow(QStandardItem("Entry %d" % (i + 1)))
  # build GUI
  win = QWidget()
  hBox = QHBoxLayout()
  lstView1 = QListView()
  lstView1.setSelectionMode(QListView.SingleSelection)
  lstView1.setModel(tblModel)
  hBox.addWidget(lstView1)
  lstView2 = QListView()
  lstView2.setSelectionMode(QListView.SingleSelection)
  lstView2.setModel(tblModel)
  hBox.addWidget(lstView2)
  lstView3 = QListView()
  lstView3.setSelectionMode(QListView.SingleSelection)
  lstView3.setModel(tblModel)
  hBox.addWidget(lstView3)
  win.setLayout(hBox)
  win.show()
  # install signal handlers
  lstViews = [lstView1, lstView2, lstView3]
  lstView1.selectionModel().selectionChanged.connect(lambda sel, unsel: singleSelect(lstView1, lstViews))
  lstView2.selectionModel().selectionChanged.connect(lambda sel, unsel: singleSelect(lstView2, lstViews))
  lstView3.selectionModel().selectionChanged.connect(lambda sel, unsel: singleSelect(lstView3, lstViews))
  # exec. application
  sys.exit(app.exec_())

从我在测试中看到的情况来看,它的行为类似于用 C++ 编写的。 唯一的例外是,当我更改列表视图时,我必须在一个条目上单击两次。

正如我已经说过的:我在 PyQt 方面的经验非常有限。 (实际上,我今天是从制作这个样本开始的。)因此,我可能监督了一些事情。请用一粒盐...

【讨论】:

  • @sunyata 我做了一个到 Python3/PyQt5 的端口。看起来还不错……但是,请考虑一下我在文末的“免责声明”。
猜你喜欢
  • 1970-01-01
  • 2015-02-21
  • 2023-01-17
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 2021-12-23
  • 2021-10-31
  • 2021-02-19
相关资源
最近更新 更多