繁体   English   中英

单击 qTableWidget pyqt5 中的特定单元格后,特定单元格的背景颜色没有改变

[英]Background color of the particular cell is not changing after clicking specific cells in qTableWidget pyqt5

所以我有一个 1 行多列的表格,我使用自定义委托 function 作为图像缩略图。 当我单击它时,我还包括了设置的背景颜色 function。 但是,它不会更改项目背景的颜色。 我必须使用自定义委托 function 以便我的图标图像从不同的单元格相互粘贴,而没有任何额外的空格。

我的代码如下

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

这是图标之间有间隙的图像,它形成的不是一个完美的箭头,这就是为什么我使用自定义委托 function 将图标粘在一起,让它看起来像一个完美的箭头

第一张图片

这是具有完美箭头外观的图像,因为使用委托 function 在单元格之间没有任何间隙。 但是,它不允许我更改单元格的背景颜色。

第二张图片

这是箭头的图像

箭头

这是箭头体的图像

箭头体

与任何重写的 function 一样,如果未调用基本实现,则忽略默认行为。

paint()是 function 负责绘制项目的任何方面,包括其背景。 由于在您的覆盖中您只是在绘制像素图,因此缺少其他所有内容,因此解决方案是调用基本实现然后绘制像素图。

但是,在这种特定情况下,这不是正确的选择,因为基本实现已经绘制了项目的装饰,并且在某些条件下(假设像素图具有 alpha 通道),它可能会导致图像重叠.

有三种可能的解决方案。

使用忽略图标的 QStyle 函数

在这种情况下,我们执行基本实现的操作,即使用 CE_ItemViewItem 调用样式drawControl CE_ItemViewItem ,但我们在此之前修改选项,删除与图标相关的任何内容:

    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 ,包括paintsizeHint 通过覆盖 function,我们可以更改绘图的某些方面,包括图标 alignment 和定位。

在这种特定情况下,知道我们只有两种类型的图标,并且它们必须根据图像右对齐或左对齐,因此更新适当的装饰尺寸(基于图标的最佳尺寸)就足够了,然后alignment 基于列。

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 使用角色来存储和检索每个索引的各个方面(字体、背景等),并且可以定义用户角色来存储自定义数据。

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM