如何设置整行而不是所有单元格的样式
how to style the entire line instead of all cells
我需要将 QTableWidget 的线四舍五入,使其看起来像这样,
但是当尝试设置边框半径时它修改了所有单元格
像这样。
我几乎没有发现关于 table 的样式不是用 C++ 编写的
或者解释了 table
中行的样式化
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_())
上面的代码有什么问题?
我认为这不可能通过设置 table 小部件的样式 sheet 实现,但可以通过将 table 的项目委托设置为自定义 QStyledItemDelegate
覆盖 paint
和 sizeHint
,例如
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()
截图:
我需要将 QTableWidget 的线四舍五入,使其看起来像这样,
但是当尝试设置边框半径时它修改了所有单元格
像这样。
我几乎没有发现关于 table 的样式不是用 C++ 编写的 或者解释了 table
中行的样式化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_())
上面的代码有什么问题?
我认为这不可能通过设置 table 小部件的样式 sheet 实现,但可以通过将 table 的项目委托设置为自定义 QStyledItemDelegate
覆盖 paint
和 sizeHint
,例如
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()
截图: