单击qTableWidget pyqt5中的特定单元格后,特定单元格的背景颜色没有改变
Posted
技术标签:
【中文标题】单击qTableWidget pyqt5中的特定单元格后,特定单元格的背景颜色没有改变【英文标题】:Background color of the particular cell is not changing after clicking specific cells in qTableWidget pyqt5 【发布时间】:2021-12-31 17:16:53 【问题描述】:所以我有一个包含 1 行和多列的表格,并且我使用自定义委托函数作为图像缩略图。单击它时,我还包括了设置背景颜色功能。但是,它不会更改项目背景的颜色。我必须使用自定义委托功能,以便我的图标图像从不同的单元格相互粘连,之间没有任何额外的空格。
我的代码如下
import random
from PyQt5 import QtCore, QtGui, QtWidgets
imagePath2 = "arrowREDHead.png"
imagePath = "arrowREDBody.png"
class IconDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
icon = index.data(QtCore.Qt.DecorationRole)
mode = QtGui.QIcon.Normal
if not (option.state & QtWidgets.QStyle.State_Enabled):
mode = QtGui.QIcon.Disabled
elif option.state & QtWidgets.QStyle.State_Selected:
mode = QtGui.QIcon.Selected
state = (
QtGui.QIcon.On
if option.state & QtWidgets.QStyle.State_Open
else QtGui.QIcon.Off
)
pixmap = icon.pixmap(option.rect.size(), mode, state)
painter.drawPixmap(option.rect, pixmap)
def sizeHint(self, option, index):
return QtCore.QSize(20, 20)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
table = QtWidgets.QTableWidget(1, 10)
delegate = IconDelegate(table)
table.setItemDelegate(delegate)
self.setCentralWidget(table)
for j in range(table.columnCount()):
if(j % 2 == 0):
pixmap = QtGui.QPixmap(imagePath)
icon = QtGui.QIcon(pixmap)
it = QtWidgets.QTableWidgetItem()
it.setIcon(icon)
table.setItem(0, j, it)
else:
pixmap = QtGui.QPixmap(imagePath2)
icon = QtGui.QIcon(pixmap)
it = QtWidgets.QTableWidgetItem()
it.setIcon(icon)
table.setItem(0, j, it)
table.item(0, 1).setBackground(QtGui.QColor(100,100,150))
table.resizeRowsToContents()
table.resizeColumnsToContents()
table.setShowGrid(False)
table.itemClicked.connect(self.sequenceClicked)
def sequenceClicked(self, item):
self.itemClicked = item
print("item", item)
item.setBackground(QtGui.QColor(255, 215, 0))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
这是图标之间有间隙的图像,它形成的箭头看起来并不完美,这就是为什么我使用自定义委托函数将图标粘在一起并让它看起来像一个完美的箭头
这是具有完美箭头外观的图像,因为它使用委托函数在单元格之间没有任何间隙。但是,它不允许我更改单元格的背景颜色。
这是箭头的图像
这是箭头的图像
【问题讨论】:
您完全覆盖了项目的绘制,因为现在您只绘制像素图,而忽略其他任何内容。您对油漆覆盖的解释也有点不清楚:“使我的图标图像从不同的单元格相互粘连”是什么意思?您能否提供您正在使用的示例图片以便我们更好地理解? 我在上面添加了两张图片。第一张图片显示了我必须使用委托函数的原因,因为两者之间存在间隙,以便它可以覆盖单元格填充并将其变成箭头而没有任何间隙,如图 2 所示。但是,有没有可能的方法来即使在我用委托函数覆盖它之后,单击时也会以某种方式更改单元格的背景颜色? 拥有实际图像会有所帮助,因为问题可能与它们的纵横比有关。 抱歉,不太清楚你的意思,你想看实际图像还是?因为我尝试使用 setIconsize 设置图像的不同纵横比,甚至设置它的缩放比例,但它不起作用。这就是我使用自定义委托函数的原因,但问题是我想在单击时实现特定单元格的更改颜色,但我想不出使用委托函数的方法 我指的是箭头图像。我可以提供一个解决方案,但是拥有这些图像会更好地确保它按您的预期正常工作。根据操作系统和风格,项目可以以非常不同的方式绘制,装饰(图标)可以有不同的边距和对齐方式。有多种可能的方法,但更好的是那些主要使用默认实现的方法,因此拥有这些图像是必不可少的,特别是如果它们没有相同的大小或比例,因为正确对齐对于您的情况是强制性的。跨度> 【参考方案1】:与任何重写的函数一样,如果未调用基本实现,则忽略默认行为。
paint()
是负责绘制项目任何方面的函数,包括其背景。由于在您的覆盖中您只是在绘制像素图,因此缺少其他所有内容,因此解决方案是调用基本实现并然后绘制像素图。
但是,在这种特定情况下,这不是正确的选择,因为基本实现已经绘制了项目的装饰,并且在某些条件下(假设像素图具有 alpha 通道),它可能会导致图像重叠。
有三种可能的解决方案。
使用 QStyle 函数忽略图标
在这种情况下,我们执行基本实现的操作,即使用 CE_ItemViewItem
调用样式 drawControl
函数,但我们在此之前修改了选项,删除了与图标相关的任何内容:
def paint(self, painter, option, index):
# create a new option (as the existing one should not be modified)
# and initialize it for the current index
option = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(option, index)
# remove anything related to the icon
option.features &= ~option.HasDecoration
option.decorationSize = QtCore.QSize()
option.icon = QtGui.QIcon()
if option.widget:
style = option.widget.style()
else:
style = QtWidgets.QApplication.style()
# call the drawing function for view items
style.drawControl(style.CE_ItemViewItem, option, painter, option.widget)
# proceed with the custom drawing of the pixmap
icon = index.data(QtCore.Qt.DecorationRole)
# ...
更新代理中的图标信息
QStyledItemDelegate 总是在其大多数函数的开头调用initStyleOption
,包括paint
和sizeHint
。通过覆盖该函数,我们可以更改绘图的某些方面,包括图标对齐和定位。
在这种特定情况下,知道我们只有两种类型的图标,并且它们必须根据图像右对齐或左对齐,更新适当的装饰尺寸(基于图标的最佳尺寸)就足够了,然后根据列对齐。
class IconDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
option.decorationSize = option.icon.actualSize(option.rect.size())
if index.column() & 1:
option.decorationPosition = option.Left
option.decorationAlignment = QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter
else:
option.decorationPosition = option.Right
option.decorationAlignment = QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter
注意:这种方法只适用于图像的比例相同且不手动更改行高的情况。
为图片使用自定义角色
Qt 使用 roles 来存储和检索每个索引的各个方面(字体、背景等),并且可以定义 user 角色来存储自定义数据。
setIcon()
实际上使用DecorationRole
在项目中设置了一个QIcon,并且委托使用它来绘制它。如果为该角色返回的数据为空/无效,则不会绘制任何图标。
如果我们不使用setIcon()
,而是使用自定义角色将图标存储在项目中,默认的绘图函数显然不会绘制任何装饰,但我们仍然可以从委托访问它。
# we usually define roles right after the imports, as they're constants
ImageRole = QtCore.Qt.UserRole + 1
class IconDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
super().paint(painter, option, index)
icon = index.data(ImageRole)
# ...
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
# ...
it = QtWidgets.QTableWidgetItem()
it.setData(ImageRole, pixmap)
【讨论】:
以上是关于单击qTableWidget pyqt5中的特定单元格后,特定单元格的背景颜色没有改变的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5 QTableWidget 禁用后如何重新启用单元格? [复制]
如何使用 PYQT5 使 QTableWidget 单元格只读?