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

如何在PySide2的QTableView中实现行悬停效果?排查代码失效问题

PySide2 QTableView行悬停背景色不生效问题修复

问题根源

  1. 默认样式覆盖设置:直接修改option.backgroundBrush后调用父类paint方法,默认的样式绘制逻辑会忽略这个修改,优先使用系统或样式表的背景配置。
  2. 悬停行跟踪逻辑缺陷:仅通过editorEvent处理单元格的MouseMove事件,无法覆盖鼠标在表格空白区域移动或移出表格的场景;且State_MouseOver是单元格级别的状态,不能直接用来判断整行悬停。

解决方法

核心思路

  • 在TableView层面监听鼠标事件,精准跟踪当前悬停的行索引,包括鼠标移出表格时重置状态。
  • 在Delegate的paint方法中,先手动绘制悬停行的背景,再调用父类方法绘制单元格内容,避免背景色被默认样式覆盖。

修改后的完整代码

import sys
from PySide2.QtGui import QColor, QBrush
from PySide2.QtWidgets import QStyledItemDelegate, QApplication, QTableView, QAbstractItemView, QStyle
from PySide2.QtCore import Qt, QModelIndex, QAbstractTableModel, QEvent


class TBV(QTableView):
    def __init__(self) -> None:
        super().__init__()
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setMouseTracking(True)
        self.hovered_row = -1  # 跟踪当前悬停的行索引

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)
        # 获取鼠标位置对应的行索引
        index = self.indexAt(event.pos())
        new_row = index.row() if index.isValid() else -1
        if new_row != self.hovered_row:
            self.hovered_row = new_row
            self.viewport().update()  # 触发视图重绘

    def leaveEvent(self, event):
        super().leaveEvent(event)
        # 鼠标离开表格时重置悬停行
        self.hovered_row = -1
        self.viewport().update()


class DEG(QStyledItemDelegate):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

    def paint(self, painter, option, index: QModelIndex) -> None:
        # 检查当前单元格所在行是否为悬停行
        if self.parent().hovered_row == index.row():
            # 手动绘制悬停行背景
            painter.fillRect(option.rect, QBrush(QColor(Qt.red)))
            # 可选:调整文字颜色避免看不清
            option.palette.setColor(option.palette.Text, Qt.white)
        
        # 调用父类绘制单元格内容
        super().paint(painter, option, index)


class MDL(QAbstractTableModel):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        self._tabledata = [['mike', 12], ['kk', 13], ['jane', 14]]

    def rowCount(self, parent: QModelIndex = ...) -> int:
        return len(self._tabledata)

    def columnCount(self, parent: QModelIndex = ...) -> int:
        return len(self._tabledata[0] if self._tabledata else [])

    def data(self, index: QModelIndex, role: int = ...):
        if not index.isValid():
            return None
        if self.rowCount() == 0:
            return None
        if index.row() >= self.rowCount():
            return None
        if role == Qt.DisplayRole or role == Qt.EditRole:
            return self._tabledata[index.row()][index.column()]
        return None


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = TBV()
    demo.setItemDelegate(DEG(demo))
    model = MDL(demo)
    demo.setModel(model)
    demo.show()
    sys.exit(app.exec_())

关键修改点

  • 在TBV类中新增hovered_row属性,通过mouseMoveEvent和leaveEvent实现全局的悬停行跟踪,覆盖所有鼠标场景。
  • 在DEG的paint方法中,先手动绘制悬停行背景,再调用父类方法绘制内容,确保背景色不会被默认样式覆盖。
  • 移除了原Delegate中冗余的currentHoveredRow和editorEvent处理逻辑,简化代码结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:11:03