簡體   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