PySide6如何使用自定义委托实现在TableWidget填充颜色
1. 实现的效果
信号在报文中的排布最直观的是用不同颜色表示,有几个信号表格中就有几种颜色,一个信号最少占用一个bit,也就是说一条长度为8个字节的报文最多可以有64种不同的颜色。需要64种不同的颜色,想要通过一个8*8的表格选取不同单元格的颜色实现采集64种不同颜色的目的。
2. 使用自定义委托实现TableWidget单元格颜色填充
在 QTableWidget 中为指定单元格设置委托并不是直接通过某个方法来实现的,因为 QTableWidget 提供的接口主要是为整行、整列或整个表格设置委托(通过 setItemDelegateForRow, setItemDelegateForColumn, 或 setItemDelegate 方法)。然而,你可以通过一些技巧来为特定的单元格实现不同的委托行为。
一种方法是使用自定义委托,并在委托内部根据单元格的索引(或其他条件)来决定如何绘制和编辑该单元格。这通常涉及到在 paint 和 createEditor 方法中添加额外的逻辑。
委托是一种用于绘制和编辑数据的对象,它允许你自定义单元格的显示和编辑行为。
自定义委托通常用于以下情况:
当你需要改变单元格的绘制方式时,比如改变文本的颜色、字体,或者添加图标、背景色等。
当你需要为单元格提供自定义的编辑器,比如一个下拉列表、一个日期选择器或是一个滑块。
当你需要处理复杂的交互逻辑,比如点击单元格时显示一个工具提示,或者实现拖放功能。
2.1 使用自定义委托实现的程序代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Logintern09
from PySide6.QtWidgets import (
QApplication,
QTableWidget,
QStyledItemDelegate,
)
from PySide6.QtGui import QColor, QPen, QBrush, QFont
from PySide6.QtCore import Qt, QRect
class ArrowDelegate(QStyledItemDelegate):
def __init__(self, color_lst, table_widget, parent=None):
super().__init__(parent)
self.color_lst = color_lst
self.table_widget = table_widget
def _cal_cell_num(self, index):
row = index.row()
column = index.column()
num = row * 8 + column
return num
def paint(self, painter, option, index):
cell_num = self._cal_cell_num(index)
color = self.color_lst[cell_num]
self._draw_cell_color(painter, option, color)
# 绘制表征单元格索引的数字
self._draw_cell_num(painter, option, index)
# 绘制表征单元格颜色的十六进制颜色数字
self._draw_color_text(painter, option, color)
def _draw_cell_color(self, painter, option, color):
# 创建一个 QBrush 对象
brush = QBrush(color)
# 使用 QPainter 的 setBrush 方法来设置填充颜色
painter.setBrush(brush)
# 绘制单元格的背景
painter.drawRect(option.rect)
def _draw_color_text(self, painter, option, color_name):
# 获取目标单元格的矩形区域
cell_rect = option.rect
# 设置文本颜色和字体(可选)
painter.setPen(QPen(QColor(0, 0, 0))) # 黑色文本
font = QFont()
font.setPointSize(5) # 设置字体大小(可选)
painter.setFont(font)
text_rect = QRect(
cell_rect.left(), # 文本左边缘与单元格左边缘对齐
cell_rect.top() + 2,
cell_rect.width(), # 文本宽度与单元格宽度相同(可以根据需要调整)
painter.fontMetrics().height(), # 文本高度
)
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, str(color_name))
def _draw_cell_num(self, painter, option, index):
# 获取目标单元格的矩形区域
cell_rect = option.rect
# 设置文本颜色和字体(可选)
painter.setPen(QPen(QColor(0, 0, 0))) # 黑色文本
font = QFont()
font.setPointSize(5) # 设置字体大小(可选)
painter.setFont(font)
# 计算文本的位置
text_rect = QRect(
cell_rect.right() - 10,
cell_rect.bottom()
- 3
- painter.fontMetrics().height(), # 距离单元格底部3像素,并减去文本高度以确保文本不超出单元格
cell_rect.width(), # 文本宽度与单元格宽度相同(可以根据需要调整)
painter.fontMetrics().height(), # 文本高度
)
cell_num = self._cal_cell_num(index)
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, str(cell_num))
class BasicTableWidget(QTableWidget):
def __init__(self, parent=None):
super(BasicTableWidget, self).__init__(parent)
self.table_widget = QTableWidget(8, 8, self)
self.table_widget.setFixedSize(700, 400) # 设置固定大小
self.table_widget.setHorizontalHeaderLabels([f"{i}" for i in range(8)])
self.table_widget.setVerticalHeaderLabels([f"{i}" for i in range(8)])
self._ini_table_style()
self.color_lst = self._get_color_lst()
def _ini_table_style(self):
# self.table_widget.verticalHeader().hide()
# self.table_widget.horizontalHeader().hide()
self.set_cell_width()
self.set_cell_height()
# Set the selection mode to allow extended (multiple) selection
self.table_widget.setSelectionMode(QTableWidget.ExtendedSelection)
style_sheet = """
QHeaderView::section {
background-color: #f0f0f0; /* 可以设置背景色为浅灰色,如果需要的话 */
color: #808080; /* 设置文字颜色为灰色 */
padding: 4px; /* 可选:设置内边距 */
border: 1px solid #d0d0d0; /* 可选:设置边框 */
}
"""
self.table_widget.setStyleSheet(style_sheet)
def set_cell_width(self):
for col in range(self.table_widget.columnCount()):
self.table_widget.setColumnWidth(col, 80)
def set_cell_height(self):
for row in range(self.table_widget.rowCount()):
self.table_widget.setRowHeight(row, 40)
def _get_color_lst(self):
color_lst = [
"#FF5733",
"#33FF57",
"#00BFFF", # 深天蓝色
"#FFBF00", # 黄橙色
"#2196F3",
"#FFEB3B",
"#4CAF50",
"#E91E63",
"#9C27B0",
"#93DB70",
"#03A9F4",
"#03DAC5",
"#00BCD4",
"#DBDB70",
"#1ABC9C",
"#2ECC71",
"#E74C3C",
"#C0392B",
"#2980B9",
"#F2784B",
"#F1C40F",
"#16A085",
"#27AE60",
"#E67E22",
"#D35400",
"#9370DB",
"#9B59B6",
"#F39C12",
"#D2B48C",
"#ECC74C",
"#3498DB",
"#9B5DE5",
"#1E90FF",
"#B22222",
"#FF1493",
"#DA70D6",
"#8A2BE2",
"#8FBC8F",
"#4682B4",
"#FAFAD2",
"#FAF0E6",
"#FFE4E1",
"#FFB6C1",
"#FFA07A",
"#FF69B4",
"#CD5C5C",
"#FFA500",
"#FFD700",
"#ADFF2F",
"#DEB887",
"#FA8072",
"#7FFF00",
"#7FFFD4",
"#00FFFF",
"#7CFC00",
"#ADD8E6",
"#E0FFFF",
"#90EE90",
"#AFEEEE",
"#DB7093",
"#FFE4B5",
"#FFDAB9",
"#FF6347",
"#FF4500",
]
return color_lst
def set_cell_style(self):
# 创建并设置自定义委托
arrow_delegate = ArrowDelegate(self.color_lst, self.table_widget)
self.table_widget.setItemDelegate(arrow_delegate)
class QLayoutWidget(BasicTableWidget):
def __init__(self, parent=None):
super(QLayoutWidget, self).__init__(parent)
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setFixedSize(700, 400)
self.set_cell_style()
if __name__ == "__main__":
app = QApplication([])
widget = QLayoutWidget()
widget.show()
app.exec()
3. 直接修改TableWidget单元格的背景颜色实现
除了上述自定义委托实现TableWidget单元格的背景颜色填充外,更为直接的方法是直接修改TableWidget单元格的背景颜色实现。
3.1 设置TableWidget单元格的背景颜色
def set_table_background_color(self, color_lst):
cell_count = -1
for row in range(self.table_widget.rowCount()):
for col in range(self.table_widget.columnCount()):
cell_count += 1
item = self.table_widget.item(row, col)
if item is None:
item = QTableWidgetItem()
self.table_widget.setItem(row, col, item)
item.setBackground(QColor(color_lst[cell_count]))
3.2 将表示颜色的十六进制数值标识在TableWidget单元格的左上角
在 PySide6(或 PyQt6)中,QTableWidget 并没有直接提供设置文本在单元格左上角显示的方法,因为通常单元格的内容是居中对齐的,并且没有内置的属性或方法来改变这种对齐方式并添加额外的文本。
你可以通过子类化 QTableWidgetItem 并重写其 paint 方法来在单元格的左上角绘制自定义文本。
重写 paint 方法:
通过重写 paint 方法,你可以完全控制单元格的绘制过程,包括文本的位置、颜色和样式。
paint 方法:
使用 painter.save() 和 painter.restore() 保存和恢复画家状态,确保对画家状态的修改不会影响后续绘制。
设置文本颜色和字体。
计算左上角文本的位置和大小。
使用 painter.drawText 在指定位置绘制文本。
class CustomTableWidgetItem(QTableWidgetItem):
def __init__(self, text, *args, **kwargs):
super().__init__(text, *args, **kwargs)
self.text = text
def paint(self, painter, option, index):
# 设置文本颜色和字体(可选)
painter.setPen(QPen(QColor(0, 0, 0))) # 黑色文本
font = QFont()
font.setPointSize(5) # 设置字体大小(可选)
painter.setFont(font)
# Calculate the position for the corner text
cell_rect = option.rect
text_rect = QRect(
cell_rect.left(), # 文本左边缘与单元格左边缘对齐
cell_rect.top() + 2,
cell_rect.width(), # 文本宽度与单元格宽度相同(可以根据需要调整)
painter.fontMetrics().height(), # 文本高度
)
# Draw the corner text
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, self.text)
painter.restore()
使用 CustomTableWidgetItem 填充表格,并设置每个单元格的左上角文本。实现写入单元格左上角文本之后的设置单元格背景的**函数set_table_background_color()**修改如下:
def set_table_background_color(self, color_lst):
cell_count = -1
for row in range(self.table_widget.rowCount()):
for col in range(self.table_widget.columnCount()):
cell_count += 1
item = self.table_widget.item(row, col)
if item is None:
item = CustomTableWidgetItem(str(color_lst[cell_count]))
self.table_widget.setItem(row, col, item)
item.setBackground(QColor(color_lst[cell_count]))
最终实现的界面效果如下: