如何在PySide2的QTableView中实现行悬停效果?排查代码失效问题
PySide2 QTableView行悬停背景色不生效问题修复
问题根源
- 默认样式覆盖设置:直接修改
option.backgroundBrush后调用父类paint方法,默认的样式绘制逻辑会忽略这个修改,优先使用系统或样式表的背景配置。 - 悬停行跟踪逻辑缺陷:仅通过
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
相关产品推荐
相关产品推荐

