PyQt QTableView 更新到 PyQt 4.5.1 后不显示图标

Posted

技术标签:

【中文标题】PyQt QTableView 更新到 PyQt 4.5.1 后不显示图标【英文标题】:PyQt QTableView not displaying icons after update to PyQt 4.5.1 【发布时间】:2010-09-23 00:30:26 【问题描述】:

我会尽量说清楚,虽然我脑子里有点糊涂。

我有一个 PyQt 应用程序已经运行了大约一年。更新到 PyQt 4.5.1(从 4.3.3)后,我的图标都不再出现在 QTableView 中(此更新与从 2.5.1 到 python 2.6.5 的更新同时进行)。恢复到较旧的 python 和 PyQt,一切都按预期工作。

细分是这样的:

我正在使用模型视图方法。我的模型,当通过 data() 方法中的 Qt.DecorationRole 请求时,将返回一个自定义对象 (ColorSwatch),它是 QIcon 类的子类。这一直有效(需要注意的是,由于我不明白的原因,我必须先将其重铸为 QVariant)。更新到 PyQt 4.5.1 后,它 似乎 可以正确运行(即我没有收到任何错误),但图标没有绘制(尽管绘制它的空间是“保留的”,即文字已向右移动,为这个不可见的图标让路)。

以下是我尝试过的一些事情:

我已验证 ColorSwatch 类仍然有效。同一个类用于将图标绘制到上下文菜单中 - 它们可以正确显示。

我已验证 data() 方法实际上被调用并返回此 ColorSwatch 对象(重铸为 QVariant

将蛇血倒在我的键盘上并点燃它。

到目前为止,还没有任何线索告诉我应该做什么。任何提示将不胜感激。谢谢。

这里是一些(可能)相关的代码(注意 paramObj.get_icon() 返回一个 ColorSwatch 对象):

#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
    """
    Returns the text or formatting for a particular cell, depending on the 
    role supplied.
    """


    blah
    blah
    blah



    elif role == QtCore.Qt.DecorationRole:
        if platform.system()=='Darwin':
            return QtGui.QIcon(paramObj.get_icon())
        else:
            return QtCore.QVariant(paramObj.get_icon())

import os
import tempfile
import sys
import colorsys
import copy
import fnmatch
import time

from PyQt4 import QtGui
from PyQt4 import QtCore


################################################################################
class ColorSwatch(QtGui.QIcon):
    """
    A subclass of QIcon, this class draws a colored paint chip with a border
    The color and size are determined at construction time, and cannot
    be changed later.
    """

    #---------------------------------------------------------------------------
    def __init__(self, r=1, g=1, b=1, br = 0, bg = 0, bb = 0, w=20, h=20):
        """
        Constructor for the ColorSwatch class. Takes the passed arguments and
        creates a square icon filled with the given color and with a border
        color determined by br, bg, bb. All colors should be in floating point
        format.
        """
        QtGui.QIcon.__init__(self)

        #normalize the color
        r8, g8, b8 = self.normalize_color((r, g, b))

        #convert the r, g, b values to 8 bit colors
        r8, g8, b8 = self.fp_to_8b_color((r8, g8, b8))

        #Create the pixmap and painter objects
        paintChip = QtGui.QPixmap(w, h)
        painter = QtGui.QPainter()
        painter.begin(paintChip)

        #fill the swatch
        baseColor = QtGui.QColor(r8, g8, b8)
        painter.fillRect(0, 0, w, h, baseColor)

        #if any of the values were super brights (>1), draw a smaller, white
        #box inset to make sure the user knows
        if r > 1 or g > 1 or b > 1:
            painter.fillRect(5, 5, w-10, h-10, QtGui.QColor(255, 255, 255))

        #if all values are 0, put a faint x through the icon
# # #         brush = QtGui.QBrush()
# # #         brush.setColor(QtGui.QColor(30, 30, 30))
        painter.setPen(QtGui.QColor(200, 200, 200))
        if r ==0 and g == 0 and b == 0:
            painter.drawLine(0, 0, w, h)
            painter.drawLine(w-1, 0, -1, h)
# # #         
# # #         #normalize the color
# # #         r8, g8, b8 = self.normalize_color((r8, g8, b8))

        #now draw the border(s)
        #convert the r, g, b values to 8 bit colors
        r8, g8, b8 = self.fp_to_8b_color((br, bg, bb))

        #draw the border
        painter.setPen(QtGui.QColor(r8, g8, b8))
        painter.drawRect(0,0,w-1,h-1)

        #if any of the values were super brights (>1), draw a border around the
        #inset box as well.
        if r > 1 or g > 1 or b > 1:
            painter.drawRect(5,5,w-11,h-11)

        #done drawing
        painter.end()

        #add it (both to the normal and the selected modes)
        self.addPixmap(paintChip, QtGui.QIcon.Normal)
        self.addPixmap(paintChip, QtGui.QIcon.Selected)


    #---------------------------------------------------------------------------
    def fp_to_8b_color(self, color):
        """
        Convert a floating point color value (passed in the form of a three 
        element tuple) to a regular 8-bit 0-255 value. Returns a 3 item tuple.
        """
        r = max(min(int(color[0]*255),255),0)
        g = max(min(int(color[1]*255),255),0)
        b = max(min(int(color[2]*255),255),0)
        return (r,g,b)


    #---------------------------------------------------------------------------
    def normalize_color(self, color):
        """
        "normalizes" a color value so that if there are any super-whites, it 
        balances all the other floating point values so that we end up with a 
        "real" color.  Negative values will result in undefined behavior.
        Mainly used to make the color chip "look right" when using super whites.
        """
        maxValue = max(color)
        if maxValue > 1:
            return (color[0]/maxValue, color[1]/maxValue, color[2]/maxValue)
        else:
            return color

【问题讨论】:

我知道一些从/到 QVariant 的自动转换在过去使用 PyQt 时发生了一些变化。试试这个:QVariant(QIcon(paramObj.get_icon()))。另外,你为什么要把达尔文的支票放在里面? 伊沃。就是这样!谢谢。 顺便说一下,我正在检查 Darwin,因为在我最初开发这个的时候,我通过反复试验发现 OSX 只会显示图标,如果它作为 QIcon 返回,而 linux 会仅当它返回 QVariant 时才有效。自从我在 OSX 上运行它以来已经有一段时间了,不知道是否仍然如此。再次感谢您的帮助! 【参考方案1】:

Ivo 在上面回答了我的问题。

实际有效的代码是:

#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
    """
    Returns the text or formatting for a particular cell, depending on the 
    role supplied.
    """


    blah
    blah
    blah



    elif role == QtCore.Qt.DecorationRole:
        if platform.system()=='Darwin':
            return QtGui.QIcon(paramObj.get_icon())
        else:
            return QtCore.QVariant(QtGui.QIcon(paramObj.get_icon()))
            #Note that it is first cast as a QIcon before
            #being cast as a QVariant.

再次感谢伊沃。

【讨论】:

以上是关于PyQt QTableView 更新到 PyQt 4.5.1 后不显示图标的主要内容,如果未能解决你的问题,请参考以下文章

将 pandas DataFrame 与 PyQt5 QTableView 同步

如何将数据发送到 QTableView/QTableWidget (PyQt)

QTableView 在 PyQt5/PySide2 中的每个选择上加载数据时锁定主窗体 [重复]

PyQt.QTableView 内容的单元测试

PyQt5在QTableview中拖拽导致选中行消失

基于 PyQt4 QTableView 模型