You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键说明

  1. 整行高亮:通过信号触发,同时处理普通单元格和控件单元格的背景色,避免高亮遗漏
  2. 行数据获取:自动识别单元格类型,优先读取控件的选中值,保证数据准确性
  3. ComboBox颜色同步:使用统一的颜色映射表,确保下拉项与控件背景颜色完全一致,修复了原Delegate中选中状态被覆盖的问题

内容的提问来源于stack exchange,提问作者Collegia Titanica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:45:38