如何设置整行而不是所有单元格的样式

Posted

技术标签:

【中文标题】如何设置整行而不是所有单元格的样式【英文标题】:how to style the entire line instead of all cells 【发布时间】:2021-03-29 01:08:47 【问题描述】:

我需要将 QTableWidget 的线四舍五入,使其看起来像这样,

但是当尝试设置边界半径时,它会修改所有单元格 像这样。

我几乎没有发现非 C++ 编写的表格样式 或者解释表中行的样式化

from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 303)
        self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.tableWidget = QtWidgets.QTableWidget(Form)
        self.tableWidget.setStyleSheet("QTableWidget\n"
        "background-color: white;\n"
        "color:black;\n"
        "border-bottom: 2px solid white;\n"
        "border-right: 2px solid white;\n"
        "\n"
        "\n"
        "QTableView::item \n"
        "border-bottom: 1px solid #d6d9dc;\n"
        "border-top: 1px solid #d6d9dc;\n"
        "margin-bottom:5px;\n"
        "border-radius:10px;\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "\n"
        "QTableView::section\n"
        "color:blue;\n"
        "")
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(3)
        self.tableWidget.setRowCount(2)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        self.tableWidget.horizontalHeader().setVisible(False)
        self.tableWidget.verticalHeader().setVisible(False)
        self.horizontalLayout.addWidget(self.tableWidget)
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)
    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        item = self.tableWidget.verticalHeaderItem(0)
        item.setText(_translate("Form", "New Row"))
        item = self.tableWidget.verticalHeaderItem(1)
        item.setText(_translate("Form", "New Row"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("Form", "New Column"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("Form", "New Column"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("Form", "New Column"))
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

上面的代码有什么问题?

【问题讨论】:

请不要将代码(包括样式表)作为图片发布,因为这会使试图重现您的问题非常烦人,因为我们需要手动复制所有内容(我们可能会犯一些错误或遗漏一些你的)。也就是说,该样式表是为表设置的还是为任何父级设置的?您确定没有在任何父小部件(包括窗口)上设置另一个(可能是通用的)样式表吗?我建议你包含 ui 文件的完整代码。 请提供minimal reproducible example M.R.E 已经在这个问题上了,抱歉之前没有发布过 @PeterTorben 抱歉,我误读了您的问题,因为我认为问题与表格的圆形边框有关。 【参考方案1】:

我认为通过设置表格小部件的样式表是不可能的,但可以通过将表格的项目委托设置为自定义QStyledItemDelegate 来覆盖paintsizeHint ,例如

from PyQt5 import QtCore, QtGui, QtWidgets


class MyStyledItem(QtWidgets.QStyledItemDelegate):
    def __init__(self, margin, radius, border_color, border_width, parent=None):
        """ 
        margin: distance between border and top of cell
        radius: radius of rounded corner
        border_color: color of border
        border_width: width of border
        """       
        super().__init__(parent)
        self.margin = margin
        self.radius = radius
        self.border_color = border_color
        self.border_width = border_width

    def sizeHint(self, option, index):
        # increase original sizeHint to accommodate space needed for border
        size = super().sizeHint(option, index)
        size = size.grownBy(QtCore.QMargins(0, self.margin, 0, self.margin))
        return size

    def paint(self, painter, option, index):
        painter.save()
        painter.setRenderHint(painter.Antialiasing)

        # set clipping rect of painter to avoid painting outside the borders
        painter.setClipping(True)
        painter.setClipRect(option.rect)
        
        # call original paint method where option.rect is adjusted to account for border
        option.rect.adjust(0, self.margin, 0, -self.margin)
        super().paint(painter, option, index)

        pen = painter.pen()
        pen.setColor(self.border_color)
        pen.setWidth(self.border_width)
        painter.setPen(pen)
        # draw either rounded rect for items in first or last column or ordinary rect
        if index.column() == 0:
            rect = option.rect.adjusted(self.border_width, 0, self.radius + self.border_width, 0)
            painter.drawRoundedRect(rect, self.radius, self.radius)
        elif index.column() == index.model().columnCount(index.parent()) - 1:
            rect = option.rect.adjusted(-self.radius-self.border_width, 0, -self.border_width, 0)
            painter.drawRoundedRect(rect, self.radius, self.radius)
        else:
            rect = option.rect.adjusted(-self.border_width, 0, self.border_width, 0)
            painter.drawRect(rect)
        # draw lines between columns
        if index.column() > 0:
            painter.drawLine(option.rect.topLeft(), option.rect.bottomLeft())
        painter.restore()

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    # create test table
    table = QtWidgets.QTableWidget()
    table.setRowCount(3)
    table.setColumnCount(3)
    for row in range(table.rowCount()):
        for col in range(table.columnCount()):
            table.setItem(row, col, QtWidgets.QTableWidgetItem(f'item at row=, col='))

    table.setShowGrid(False)
    delegate = MyStyledItem(margin=3, radius=10, border_width=2, border_color=QtGui.QColor("navy"))
    table.setItemDelegate(delegate)
    # the custom styled item delegate can be used with a style sheet
    table.setStyleSheet("QTableView::item border: 0px; padding: 10px; ")
    # next line is needed to call the sizeHint of the item delegate
    table.resizeRowsToContents()
    table.show()
    app.exec()

截图:

【讨论】:

感谢您的回答,我从来没有在 pyqt5 中遇到过委托,这是一个很棒的学习。

以上是关于如何设置整行而不是所有单元格的样式的主要内容,如果未能解决你的问题,请参考以下文章

QTableView 中的着色行而不是单元格

html中,如何固定table单元格宽度?

如何自定义 Material ui 表格单元格,以便其中的文本将占用两行而不是一行?

java poi编写代码来设置Excel单元格的样式

如何以分组样式设置 UITableView 中单元格的宽度

如何更改 JQuery.DataTable 中单元格的样式?