如何在不修改选择模式和样式表的情况下禁用QTableWidget选中单元格高亮?
问题
现有一个实现了单元格颜色切换的网格示例,但运行时自定义设置的单元格颜色会被选中高亮效果遮挡。要求不能修改选择模式(需保留选择范围以实现单行内批量单元格上色),也不能调整样式表(避免多行单元格被高亮),问是否可以完全禁用/绕过高亮颜色的绘制事件?
示例代码:
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setGeometry(100, 100, 750, 750) self.rows=60 self.columns=50 self.tableWidget=QTableWidget(self.rows, self.columns) self.tableWidget.horizontalHeader().hide() self.tableWidget.verticalHeader().hide() self.activated={} self.item={} for r in range(self.rows): for c in range(self.columns): self.activated[r,c]=False self.item[r,c]=QTableWidgetItem() self.tableWidget.setItem(r,c,self.item[r,c]) self.tableWidget.setFocusPolicy(Qt.NoFocus) #self.tableWidget.setSelectionMode(QAbstractItemView.NoSelection) #self.tableWidget.setStyleSheet("""QTableView:item:selected{selection-background-color: rgb(100,100,150);}""") #self.tableWidget.setStyleSheet("""QTableView:item:selected{selection-background-color: transparent;}""") self.tableWidget.setEditTriggers(QTableWidget.NoEditTriggers) self.tableWidget.cellClicked.connect(self.dothing) self.tableWidget.cellDoubleClicked.connect(self.dothing) self.setCentralWidget(self.tableWidget) def dothing(self,r,c): if self.activated[r,c]: self.activated[r,c]=False self.item[r,c].setBackground(QColor(255,255,255)) else: # 修正原代码笔误:循环变量应为row而非column,避免键不存在错误 for row in range(self.rows): self.activated[row,c]=False self.item[row,c].setBackground(QColor(255,255,255)) self.activated[r,c]=True self.item[r,c].setBackground(QColor(100,100,150)) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()
解决方案
可以通过自定义QTableWidgetItem并重写其paint方法绕过高亮颜色绘制,完全控制单元格背景显示,同时保留选择功能。
核心思路:在绘制单元格时,移除选中状态标记,让Qt不再绘制高亮背景,直接使用自定义设置的背景色,同时保留文本等其他内容的正常绘制。
修改后的完整代码:
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class CustomTableItem(QTableWidgetItem): def paint(self, painter, option, index): # 复制选项对象,避免修改原对象影响其他单元格绘制 opt = QStyleOptionViewItem(option) # 移除选中状态标记,取消高亮背景绘制 opt.state &= ~QStyle.State_Selected # 调用父类paint方法,使用修改后的选项 super().paint(painter, opt, index) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setGeometry(100, 100, 750, 750) self.rows=60 self.columns=50 self.tableWidget=QTableWidget(self.rows, self.columns) self.tableWidget.horizontalHeader().hide() self.tableWidget.verticalHeader().hide() self.activated={} self.item={} for r in range(self.rows): for c in range(self.columns): self.activated[r,c]=False # 使用自定义单元格类替代默认类 self.item[r,c]=CustomTableItem() self.tableWidget.setItem(r,c,self.item[r,c]) self.tableWidget.setFocusPolicy(Qt.NoFocus) self.tableWidget.setEditTriggers(QTableWidget.NoEditTriggers) self.tableWidget.cellClicked.connect(self.dothing) self.tableWidget.cellDoubleClicked.connect(self.dothing) self.setCentralWidget(self.tableWidget) def dothing(self,r,c): if self.activated[r,c]: self.activated[r,c]=False self.item[r,c].setBackground(QColor(255,255,255)) else: for row in range(self.rows): self.activated[row,c]=False self.item[row,c].setBackground(QColor(255,255,255)) self.activated[r,c]=True self.item[r,c].setBackground(QColor(100,100,150)) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()
关键说明
- 自定义
CustomTableItem类通过修改绘制选项,彻底取消了选中高亮背景的绘制,完全保留自定义背景色的显示。 - 原有的选择功能不受影响,依然可以通过
selectedItems()等方法获取选中单元格,满足单行批量上色的需求。 - 无需修改选择模式或样式表,完美规避高亮遮挡自定义颜色的问题。
内容的提问来源于stack exchange,提问作者rllysleepy
相关产品推荐
相关产品推荐

