从QTableWidget单元格内的QCheckBox获取状态

时间:2020-02-23 08:34:47

标签: python pyqt5 qtablewidget qcheckbox

我想从QTableWidget单元内的QCheckBox获取状态。 我已经为此问题制作了示例代码。

import sys
from PyQt5.QtCore import Qt, QSettings
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton, QTableWidget, QCheckBox, QTextEdit


class TestUI(QWidget):
    def __init__(self):
        super().__init__()

        self.btn = QPushButton("Get Data")
        self.tbl = QTableWidget()
        self.log = QTextEdit()

        self.init_ui()

    def init_ui(self):
        self.btn.clicked.connect(self.get_data)

        self.tbl.setFocusPolicy(Qt.NoFocus)
        self.tbl.setMinimumHeight(255)
        self.tbl.setMaximumHeight(255)
        self.tbl.setRowCount(20)
        self.tbl.setColumnCount(3)
        self.tbl.horizontalHeader().setStretchLastSection(True)
        self.tbl.setHorizontalHeaderLabels(["", "Option", "Value"])
        self.tbl.resizeRowsToContents()
        self.tbl.resizeColumnsToContents()
        for row in range(20):
            chk_box = QCheckBox()
            chk_box.setCheckState(Qt.Unchecked)
            cell = QWidget()
            hlayout = QHBoxLayout()
            hlayout.addWidget(chk_box)
            hlayout.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
            hlayout.setContentsMargins(0, 0, 0, 0)
            cell.setLayout(hlayout)
            self.tbl.setCellWidget(row, 0, cell)

        vlayout = QVBoxLayout()
        vlayout.addWidget(self.btn)
        vlayout.addWidget(self.tbl)
        vlayout.addWidget(self.log)

        self.setLayout(vlayout)
        self.show()

    def get_data(self):
        self.log.clear()
        self.log.append(self.tbl.cellWidget(0, 0).isChecked())
        self.log.append(self.tbl.cellWidget(0, 1).text())
        self.log.append(self.tbl.cellWidget(0, 2).text())


if __name__ == "__main__":
    APP = QApplication(sys.argv)
    ex = TestUI()
    sys.exit(APP.exec_())

我该怎么做?我无法通过此代码获取状态。

我认为代码应为self.log.append(self.tbl.cellWidget(0, 0).????.isChecked())

但是我不知道该怎么做。

请帮助我。

1 个答案:

答案 0 :(得分:2)

如果分析了将小部件置于第0列的代码:

chk_box = QCheckBox()
chk_box.setCheckState(Qt.Unchecked)
cell = QWidget()
hlayout = QHBoxLayout()
hlayout.addWidget(chk_box)
hlayout.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
hlayout.setContentsMargins(0, 0, 0, 0)
cell.setLayout(hlayout)
self.tbl.setCellWidget(row, 0, cell)

请注意,窗口小部件集不是QCheckBox而是QWidget,并且QCheckBox是QWidget的儿子,因此可以使用findChild()方法获取信息。另一方面,item方法可能返回None,因此您应该检查它是否不是,因为它可能会引发异常:

def get_data(self):
    self.log.clear()
    widget = self.tbl.cellWidget(0, 0)
    if widget is not None:
        chk_box = widget.findChild(QCheckBox)
        if chk_box is not None:
            self.log.append(str(chk_box.isChecked()))
    it1 = self.tbl.item(0, 1)
    self.log.append(it1.text() if it1 is not None else "")
    it2 = self.tbl.item(0, 2)
    self.log.append(it2.text() if it2 is not None else "")

上述方法的一个更优雅的版本是使“单元格”成为一个自定义小部件,该小部件公开了QCheckBox的isChecked()方法:

class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.chk_box = QCheckBox()
        self.chk_box.setCheckState(Qt.Unchecked)
        hlayout = QHBoxLayout(self)
        hlayout.addWidget(self.chk_box)
        hlayout.setAlignment(Qt.AlignCenter)
        hlayout.setContentsMargins(0, 0, 0, 0)

    def isChecked(self):
        return self.chk_box.isChecked()


class TestUI(QWidget):
    def __init__(self):
        super().__init__()

        self.btn = QPushButton("Get Data")
        self.tbl = QTableWidget()
        self.log = QTextEdit()

        self.init_ui()

    def init_ui(self):
        self.btn.clicked.connect(self.get_data)

        self.tbl.setFocusPolicy(Qt.NoFocus)
        self.tbl.setMinimumHeight(255)
        self.tbl.setMaximumHeight(255)
        self.tbl.setRowCount(20)
        self.tbl.setColumnCount(3)
        self.tbl.horizontalHeader().setStretchLastSection(True)
        self.tbl.setHorizontalHeaderLabels(["", "Option", "Value"])
        self.tbl.resizeRowsToContents()
        self.tbl.resizeColumnsToContents()
        for row in range(20):
            cell = Widget()
            self.tbl.setCellWidget(row, 0, cell)
        vlayout = QVBoxLayout(self)
        vlayout.addWidget(self.btn)
        vlayout.addWidget(self.tbl)
        vlayout.addWidget(self.log)
        self.show()

    def get_data(self):
        self.log.clear()
        widget = self.tbl.cellWidget(0, 0)
        if widget is not None:
            self.log.append(str(widget.isChecked()))
        it1 = self.tbl.item(0, 1)
        self.log.append(it1.text() if it1 is not None else "")
        it2 = self.tbl.item(0, 2)
        self.log.append(it2.text() if it2 is not None else "")

可以推断出您使用QWidget将QCheckBox置于单元格内部居中,但我认为可以对其进行优化以避免使用QProxyStyle创建小部件,然后通过QTableWidgetItem的checkState()方法访问信息: / p>

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
    QApplication,
    QWidget,
    QHBoxLayout,
    QVBoxLayout,
    QPushButton,
    QTableWidget,
    QTextEdit,
    QTableWidgetItem,
    QProxyStyle,
    QStyle,
)


class ProxyStyle(QProxyStyle):
    def subElementRect(self, element, option, widget):
        r = super().subElementRect(element, option, widget)
        if element == QStyle.SE_ItemViewItemCheckIndicator:
            r.moveCenter(option.rect.center())
        return r


class TestUI(QWidget):
    def __init__(self):
        super().__init__()
        self.btn = QPushButton("Get Data")
        self.tbl = QTableWidget()
        self.log = QTextEdit()
        self.init_ui()

    def init_ui(self):
        self.btn.clicked.connect(self.get_data)

        proxy = ProxyStyle()
        self.tbl.setStyle(proxy)
        self.tbl.setFocusPolicy(Qt.NoFocus)
        self.tbl.setFixedHeight(255)
        self.tbl.setRowCount(20)
        self.tbl.setColumnCount(3)
        self.tbl.horizontalHeader().setStretchLastSection(True)
        self.tbl.setHorizontalHeaderLabels(["", "Option", "Value"])
        self.tbl.resizeRowsToContents()
        self.tbl.resizeColumnsToContents()
        for row in range(20):
            it = QTableWidgetItem()
            it.setCheckState(Qt.Checked)
            self.tbl.setItem(row, 0, it)
        vlayout = QVBoxLayout(self)
        vlayout.addWidget(self.btn)
        vlayout.addWidget(self.tbl)
        vlayout.addWidget(self.log)
        self.show()

    def get_data(self):
        self.log.clear()
        it0 = self.tbl.item(0, 0)
        self.log.append(str(it0.checkState() == Qt.Checked))
        it1 = self.tbl.item(0, 1)
        self.log.append(it1.text() if it1 is not None else "")
        it2 = self.tbl.item(0, 2)
        self.log.append(it2.text() if it2 is not None else "")


if __name__ == "__main__":
    APP = QApplication(sys.argv)
    ex = TestUI()
    sys.exit(APP.exec_())