PyQt6 - 选择项目时如何在 table 视图中选中复选框

PyQt6 - How to check a checkbox within table view when selecting an item

我有一个带复选框的单列 TableView。我想在选中一个项目时选中该复选框,而在选中一个复选框时则相反,项目也应该处于选中状态。 我有一个问题,因为我在 QSortFilterProxyModel 中设置了 table,当过滤并选择了一个项目时,行号也会根据过滤器发生变化。所以我无法在 QStandardItemModel 中获取实际项目。例如,如果我过滤并检查了第 3 个项目,则所选项目将是处于初始状态的项目。

我的代码如下:

class WindowHomeScreen(QtWidgets.QMainWindow):
    """Main Screen of the application"""

    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.menu_items = {}
        self.is_all_selected = False  # Table items
        self.filter_proxy_model = QtCore.QSortFilterProxyModel()

        articles = sql_db.query_fetch_articles_list()
        self.fixed_rates = sql_db.query_fetch_fixed_rates()
        self.model = QtGui.QStandardItemModel(len(articles), 1)
        self.model.setHorizontalHeaderLabels(["Articles"])
        self.articles_dict: dict[str, tuple[Article, PriceStructure, OSCharges]] = {}
        for row, article in enumerate(articles):
            if article[0].mrp != 0:
                key = f"{article[0].article}  - ₹{article[0].mrp}"
            else:
                key = f"{article[0].article}  - ###"
            item = QtGui.QStandardItem(key)
            self.articles_dict[key] = article
            item.setFlags(
                Qt.ItemFlag.ItemIsUserCheckable
                | Qt.ItemFlag.ItemIsEnabled
                | Qt.ItemFlag.ItemIsSelectable
            )
            item.setCheckState(Qt.CheckState.Unchecked)
            self.model.setItem(row, 0, item)
        self.filter_proxy_model.setSourceModel(self.model)
        self.filter_proxy_model.setFilterCaseSensitivity(
            Qt.CaseSensitivity.CaseInsensitive
        )
        self.filter_proxy_model.setFilterKeyColumn(0)

        # Connections with filter
        self.ui.lineEdit.textChanged.connect(
            self.filter_proxy_model.setFilterRegularExpression
        )
        self.ui.tableView.horizontalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.ResizeMode.Stretch
        )
        self.ui.tableView.setEditTriggers(
            QtWidgets.QTableView.EditTrigger.NoEditTriggers
        )
        self.ui.tableView.setModel(self.filter_proxy_model)
        self.ui.tableView.doubleClicked.connect(self.tableDoubleClicked)
        self.ui.tableView.clicked.connect(self.tableSingleClicked)
        self.ui.tableView.selectionModel().selectionChanged.connect(
            self.tableSelectionChanged
        )
        self.ui.tableView.findChild(QtWidgets.QAbstractButton).clicked.connect(
            self.tableSelectAll
        )

        # Connections to buttons
        self.ui.button_show_stats.clicked.connect(self.buttonShowStats)
        self.ui.button_export_xl.clicked.connect(self.buttonExport)
        self.ui.button_export_summary.clicked.connect(self.buttonExportSummaryReport)
        # TODO: Create new method to export only currently displaying item
        self.ui.button_export_xl_sub.clicked.connect(self.buttonExport)

        # Connections to menu items
        self.ui.actionClose.triggered.connect(self.menu_close_app)
        self.ui.actionUpgradeBom.triggered.connect(self.menu_create_bom)
        self.ui.actionUpgradeOS_Charge.triggered.connect(self.menu_create_osc)
        self.ui.actionUpgradePrice_Structure.triggered.connect(self.menu_create_ps)
        self.ui.actionUpdateOS_Charges.triggered.connect(self.menu_manage_osc)
        self.ui.actionUpdatePrice_Structure.triggered.connect(self.menu_manage_ps)
        self.ui.actionUpdateOther_Expenses.triggered.connect(self.menu_manage_expenses)
        self.ui.actionUpdateFixed_Charges.triggered.connect(
            self.menu_manage_fixed_charges
        )

    def tableSelectAll(self):
        """Select or Unselect all check boxes in the table

        Table View corner button function.
        """
        if self.is_all_selected:
            self.ui.tableView.clearSelection()
        self.is_all_selected = not self.is_all_selected

    def tableSelectionChanged(
        self, selected: QtCore.QItemSelection, deselected: QtCore.QItemSelection
    ):
        """Catch Selection changed behaviour"""

        for item in selected.indexes():
            self.model.item(item.row(), 0).setCheckState(Qt.CheckState.Checked)

        for item in deselected.indexes():
            self.model.item(item.row(), 0).setCheckState(Qt.CheckState.Unchecked)

    def tableSingleClicked(self, modelIndex: QtCore.QModelIndex):
        """Single clicked item in the tableview

        Select or Unselect item.
        """
        if (
            self.model.item(modelIndex.row(), 0).checkState() == Qt.CheckState.Checked
            and modelIndex not in self.ui.tableView.selectedIndexes()
        ) or (
            self.model.item(modelIndex.row(), 0).checkState() == Qt.CheckState.Unchecked
            and modelIndex in self.ui.tableView.selectedIndexes()
        ):

            self.ui.tableView.selectionModel().select(
                modelIndex, QtCore.QItemSelectionModel.SelectionFlag.Toggle
            )

# rest of the code...

感谢:@musicamante ;

我可以通过如下修改我的选择更改方法和单项单击方法来解决问题;

     def tableSelectionChanged(
         self, selected: QtCore.QItemSelection, deselected: QtCore.QItemSelection
     ):
         """Catch Selection changed behaviour"""
 
         for index in selected.indexes():
             self.filter_proxy_model.setData(index, Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole) 
         for index in deselected.indexes():
             self.filter_proxy_model.setData(index, Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole) 
 
     def tableSingleClicked(self, modelIndex: QtCore.QModelIndex):
         """Single item clicked/checked in the tableview
 
         Select or Unselect item when checkbox is checked or unchecked.
         
         """
         # CheckState key is 10 in itemData - Not read doc for info
         # check_state will be Qt.CheckState "enum value" when checkbox item is checked.
         # check_state will be Qt.CheckState "enum" when item selected.
         # only checkbox item selection is needed, so integer value will consider in here and other ignored which isn't needed.
         check_state = self.filter_proxy_model.itemData(modelIndex).get(10)
         if (
             check_state == 2
             and modelIndex not in self.ui.tableView.selectedIndexes()
         ) or (
             check_state == 0
             and modelIndex in self.ui.tableView.selectedIndexes()
         ):
             self.ui.tableView.selectionModel().select(
                 modelIndex, QtCore.QItemSelectionModel.SelectionFlag.Toggle
             )