Получить состояние из QCheckBox внутри ячейки QTableWidget - PullRequest
1 голос
/ 23 февраля 2020

Я хочу получить состояние из QCheckBox внутри ячейки QTableWidget. Я сделал пример кода для этой проблемы.

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()).

Но я не знаю точно, как это сделать.

Пожалуйста, помогите мне.

Ответы [ 2 ]

2 голосов
/ 23 февраля 2020

Если анализируется код, который помещает виджет в столбец 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 "")

Более элегантная версия вышеприведенного - сделать «ячейка» - это пользовательский виджет, который предоставляет метод isChecked () QCheckBox:

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, а затем обращаться к информации через метод checkState () класса QTableWidgetItem:

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_())
0 голосов
/ 23 февраля 2020

Почему вы сначала помещаете QCheckBox в QWidget, а затем помещаете его в QTableWidget? Это будет выглядеть так же, если вы просто поместите QCheckBox напрямую. И теперь cellWidget() вернет QCheckBox вместо QWidget.

for row in range(20):
    chk_box = QCheckBox()
    chk_box.setCheckState(Qt.Unchecked)
    self.tbl.setCellWidget(row, 0, chk_box)

Кроме того, все, что вы добавляете в QTextEdit, должно быть str, а состояние флажка - bool, поэтому измените эту строку:

self.log.append(str(self.tbl.cellWidget(0, 0).isChecked()))
...