PyQt5实现表格行选中高亮与ComboBox选中项背景着色
PyQt5项目需求解决方案
需求1:QTableWidget整行高亮与行数据获取
实现逻辑
- 绑定表格
itemClicked信号,点击单元格时触发整行高亮处理 - 维护上次高亮行的索引,避免重复高亮或残留背景色
- 编写专用函数,统一获取选中行的所有列数据(兼容普通单元格和控件类型单元格)
代码实现
在MainWindow类中添加以下内容:
def __init__(self): # 原有初始化代码... self.ShotTable.itemClicked.connect(self.highlight_selected_row) self.last_highlighted_row = -1 def highlight_selected_row(self, item): # 清除上一行的高亮状态 if self.last_highlighted_row != -1: for col in range(self.ShotTable.columnCount()): # 处理普通单元格 cell_item = self.ShotTable.item(self.last_highlighted_row, col) if cell_item: cell_item.setBackground(QtGui.QColor(Qt.white)) # 处理单元格内的控件(如ComboBox) cell_widget = self.ShotTable.cellWidget(self.last_highlighted_row, col) if cell_widget: cell_widget.setStyleSheet("background-color: white;") # 设置当前行为浅白色高亮 current_row = item.row() self.last_highlighted_row = current_row light_white = QtGui.QColor("#f0f0f0") for col in range(self.ShotTable.columnCount()): cell_item = self.ShotTable.item(current_row, col) if cell_item: cell_item.setBackground(light_white) cell_widget = self.ShotTable.cellWidget(current_row, col) if cell_widget: cell_widget.setStyleSheet(f"background-color: {light_white.name()};") def get_selected_row_data(self): if self.last_highlighted_row == -1: return None row_data = [] for col in range(self.ShotTable.columnCount()): # 优先获取控件类单元格的数据 cell_widget = self.ShotTable.cellWidget(self.last_highlighted_row, col) if isinstance(cell_widget, MyQComboBox): row_data.append(cell_widget.currentText()) else: # 获取普通单元格文本 cell_item = self.ShotTable.item(self.last_highlighted_row, col) row_data.append(cell_item.text() if cell_item else "") return row_data
需求2:QComboBox背景与选中项颜色同步
实现逻辑
- 统一维护状态与颜色的映射关系,避免代码重复
- 修复
StatusItemDelegate的绘制逻辑,确保选中状态显示正常 - 为
MyQComboBox添加选中项变化监听,动态同步背景色
代码实现
1. 定义全局状态颜色映射
在代码开头添加:
# 状态与颜色映射,索引与STATUS列表顺序一一对应 STATUS_COLORS = [ QtGui.QColor(228, 221, 131), # Initializing ... QtGui.QColor(185, 183, 159), # Not Started QtGui.QColor(65, 203, 53), # Track QtGui.QColor(38, 121, 31), # Track Approval QtGui.QColor(31, 121, 104), # For Solving QtGui.QColor(48, 216, 226), # Solve QtGui.QColor(226, 167, 48), # For GeoBuild QtGui.QColor(226, 142, 48), # GeoBuild QtGui.QColor(243, 222, 108), # For Rotomation QtGui.QColor(243, 141, 108), # Rotomation QtGui.QColor(154, 76, 79), # Waiting Assets QtGui.QColor(76, 112, 154), # For Packing QtGui.QColor(53, 89, 201), # Packing QtGui.QColor(114, 228, 118), # Preview QtGui.QColor(178, 114, 228), # Ready QtGui.QColor(147, 169, 236), # For Delivery QtGui.QColor(81, 50, 199), # Delivered QtGui.QColor(84, 95, 239), # Approved QtGui.QColor(239, 84, 84), # Cancelled QtGui.QColor(98, 81, 81), # On Hold QtGui.QColor(98, 1, 1) # Got Issue! ]
2. 修改StatusItemDelegate类
class StatusItemDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent=parent) def paint(self, painter, option, index): color = STATUS_COLORS[index.row()] # 先处理选中状态的背景高亮 if option.state & QtWidgets.QStyle.State_Selected: painter.fillRect(option.rect, option.palette.highlight()) # 填充状态对应的颜色 painter.save() painter.fillRect(option.rect, QtGui.QBrush(color)) painter.restore() # 调用父类绘制文本内容 super().paint(painter, option, index)
3. 修改MyQComboBox类
class MyQComboBox(QtWidgets.QComboBox): def __init__(self, scrollWidget=None, *args, **kwargs): super().__init__(*args, **kwargs) self.scrollWidget=scrollWidget self.setFocusPolicy(QtCore.Qt.StrongFocus) # 绑定选中项变化信号,同步背景色 self.currentIndexChanged.connect(self.update_background_color) # 初始化时设置默认背景色 self.update_background_color(self.currentIndex()) def wheelEvent(self, *args, **kwargs): return def update_background_color(self, index): if 0 <= index < len(STATUS_COLORS): color = STATUS_COLORS[index] self.setStyleSheet(f"QComboBox {{ background-color: {color.name()}; }}") else: self.setStyleSheet("")
完整修改后的代码
import sys from PyQt5 import QtCore, QtGui, QtWidgets, uic from PyQt5.QtCore import QSize, Qt from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QTableWidget, QStyledItemDelegate # 状态与颜色映射,索引与STATUS列表顺序一一对应 STATUS_COLORS = [ QtGui.QColor(228, 221, 131), # Initializing ... QtGui.QColor(185, 183, 159), # Not Started QtGui.QColor(65, 203, 53), # Track QtGui.QColor(38, 121, 31), # Track Approval QtGui.QColor(31, 121, 104), # For Solving QtGui.QColor(48, 216, 226), # Solve QtGui.QColor(226, 167, 48), # For GeoBuild QtGui.QColor(226, 142, 48), # GeoBuild QtGui.QColor(243, 222, 108), # For Rotomation QtGui.QColor(243, 141, 108), # Rotomation QtGui.QColor(154, 76, 79), # Waiting Assets QtGui.QColor(76, 112, 154), # For Packing QtGui.QColor(53, 89, 201), # Packing QtGui.QColor(114, 228, 118), # Preview QtGui.QColor(178, 114, 228), # Ready QtGui.QColor(147, 169, 236), # For Delivery QtGui.QColor(81, 50, 199), # Delivered QtGui.QColor(84, 95, 239), # Approved QtGui.QColor(239, 84, 84), # Cancelled QtGui.QColor(98, 81, 81), # On Hold QtGui.QColor(98, 1, 1) # Got Issue! ] class MyQComboBox(QtWidgets.QComboBox): def __init__(self, scrollWidget=None, *args, **kwargs): super().__init__(*args, **kwargs) self.scrollWidget=scrollWidget self.setFocusPolicy(QtCore.Qt.StrongFocus) self.currentIndexChanged.connect(self.update_background_color) self.update_background_color(self.currentIndex()) def wheelEvent(self, *args, **kwargs): return def update_background_color(self, index): if 0 <= index < len(STATUS_COLORS): color = STATUS_COLORS[index] self.setStyleSheet(f"QComboBox {{ background-color: {color.name()}; }}") else: self.setStyleSheet("") class StatusItemDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent=parent) def paint(self, painter, option, index): color = STATUS_COLORS[index.row()] if option.state & QtWidgets.QStyle.State_Selected: painter.fillRect(option.rect, option.palette.highlight()) painter.save() painter.fillRect(option.rect, QtGui.QBrush(color)) painter.restore() super().paint(painter, option, index) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.UI=uic.loadUi('VertigoCentral.ui', self) self.TYPE = ("UV","LD") self.STATUS = ("Initializing ...","Not Started","Track","Track Approval", "For Solving", "Solve", "For GeoBuild", "GeoBuild", "For Rotomation", "Rotomation","Waiting Assets", "For Packing", "Packing","Preview","Ready", "For Delivery","Delivered","Approved", "Cancelled","On Hold","Got Issue!") self.ShotTable.itemClicked.connect(self.highlight_selected_row) self.last_highlighted_row = -1 def highlight_selected_row(self, item): if self.last_highlighted_row != -1: for col in range(self.ShotTable.columnCount()): cell_item = self.ShotTable.item(self.last_highlighted_row, col) if cell_item: cell_item.setBackground(QtGui.QColor(Qt.white)) cell_widget = self.ShotTable.cellWidget(self.last_highlighted_row, col) if cell_widget: cell_widget.setStyleSheet("background-color: white;") current_row = item.row() self.last_highlighted_row = current_row light_white = QtGui.QColor("#f0f0f0") for col in range(self.ShotTable.columnCount()): cell_item = self.ShotTable.item(current_row, col) if cell_item: cell_item.setBackground(light_white) cell_widget = self.ShotTable.cellWidget(current_row, col) if cell_widget: cell_widget.setStyleSheet(f"background-color: {light_white.name()};") def get_selected_row_data(self): if self.last_highlighted_row == -1: return None row_data = [] for col in range(self.ShotTable.columnCount()): cell_widget = self.ShotTable.cellWidget(self.last_highlighted_row, col) if isinstance(cell_widget, MyQComboBox): row_data.append(cell_widget.currentText()) else: cell_item = self.ShotTable.item(self.last_highlighted_row, col) row_data.append(cell_item.text() if cell_item else "") return row_data app = QApplication(sys.argv) window = MainWindow() window.setFixedSize(1920, 1080) for row in range(window.ShotTable.rowCount()): window.ShotTable.setRowHeight(row,36) cmbOption = MyQComboBox() cmbOption.setObjectName("Status") for index,it in enumerate(window.STATUS): cmbOption.addItem(it) cmbOption.setItemDelegate(StatusItemDelegate()) window.ShotTable.setCellWidget(row, 5, cmbOption) view = cmbOption.view() view.setFixedHeight(570) window.ShotTable.setFocusPolicy(Qt.NoFocus) window.show() app.exec()
关键说明
- 整行高亮:通过信号触发,同时处理普通单元格和控件单元格的背景色,避免高亮遗漏
- 行数据获取:自动识别单元格类型,优先读取控件的选中值,保证数据准确性
- ComboBox颜色同步:使用统一的颜色映射表,确保下拉项与控件背景颜色完全一致,修复了原Delegate中选中状态被覆盖的问题
内容的提问来源于stack exchange,提问作者Collegia Titanica
相关产品推荐
相关产品推荐

