在pyqt5的qtableview列中添加居中对齐的复选框

add checkbox with center alignment in a column of qtableview in pytq5

我想在我的 qtableview 中添加一列复选框。我需要复选框位于列的中心(即居中对齐)。我有这个工作正常的例子,但复选框左对齐。

import sys
import pandas as pd
from PyQt5 import QtCore, Qt
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QCheckBox, QHBoxLayout, QItemDelegate, QTableView, QWidget, QApplication, QMainWindow


class MyCheckboxDelegate(QItemDelegate):
  
    def __init__(self, parent):
        QItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        check = QCheckBox(parent)
        check.clicked.connect(self.currentIndexChanged)
        return check

    def setModelData(self, editor, model, index):
        model.setData(index, editor.checkState())

    @pyqtSlot()
    def stateChanged(self):
        self.commitData.emit(self.sender())

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        print(data)
        self._data = data

    def rowCount(self, index=None):
        return self._data.shape[0]

    def columnCount(self, parnet=None):
        return self._data.shape[1]

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
                if self._data.columns[index.column()]=='Delete':
                    return ''
                value = self._data.iloc[index.row(), index.column()]
                return str(value)
class MyWindow(QMainWindow):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        table_model = TableModel(pd.DataFrame([['', ''], ['','']]))
        self.table_view = QTableView()
        self.table_view.setModel(table_model)
        self.table_view.setItemDelegateForColumn(0, MyCheckboxDelegate(self))

        for row in range(0, table_model.rowCount()):
            self.table_view.openPersistentEditor(table_model.index(row, 0))
        self.setCentralWidget(self.table_view)

app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

为了强制它们居中,我创建了一个小部件,添加了一个布局并将复选框添加到布局中。也就是说,我把MyCheckboxDelegatecreateEditor函数改成如下:

def createEditor(self, parent, option, index):
    w = QWidget(parent)
    layout = QHBoxLayout(w)
    check = QCheckBox(parent)
    check.clicked.connect(self.currentIndexChanged)
    check.setStyleSheet("color: red;")
    layout.addWidget(check)
    layout.setAlignment(Qt.AlignCenter)
    return w

问题是现在 setModelData 将不再被调用。单击复选框后,我需要访问“模型”。

有人知道如何解决吗?

只要编辑器有 user property,项目委托就可以设置模型数据,而基本的 QWidget 则没有。

解决方案是创建一个实现该 属性 的 QWidget 子类,并将复选框连接到一个实际上与以前相同的信号:

class CenterCheckBox(QWidget):
    toggled = pyqtSignal(bool)
    def __init__(self, parent):
        super().__init__(parent)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        self.check = QCheckBox()
        layout.addWidget(self.check, alignment=Qt.AlignCenter)
        self.check.setFocusProxy(self)
        self.check.toggled.connect(self.toggled)
        # set a 0 spacing to avoid an empty margin due to the missing text
        self.check.setStyleSheet('color: red; spacing: 0px;')

    @pyqtProperty(bool, user=True) # note the user property parameter
    def checkState(self):
        return self.check.isChecked()

    @checkState.setter
    def checkState(self, state):
        self.check.setChecked(state)


class MyCheckboxDelegate(QStyledItemDelegate):
    def __init__(self, parent):
        super().__init__(parent)

    def createEditor(self, parent, option, index):
        check = CenterCheckBox(parent)
        check.toggled.connect(lambda: self.commitData.emit(check))
        return check

    def setModelData(self, editor, model, index):
        model.setData(index, editor.checkState)

注意:

  • 通常使用QStyledItemDelegate比较好,更符合应用程序的整体外观;
  • 您应该始终在返回编辑器之前检查列(或行),并在 setModelData() 中执行相同的操作(或至少检查编辑器),或者使用 setItemDelegateForColumn();