qtablevi中意外填充pyqt

2024-03-28 20:35:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试为QTableView创建一个自定义的TableModel类。包含1作为数据的单元格必须具有红色大纲。大纲是通过从TableModel返回一个pixmap(在顶部绘制红色边框和文本)而不是返回一个简单的字符串。在

问题在于pixmap的意外填充,我返回为DecorationRole。我检查了pixmap是否绘制正确(实际上它是21x21px,轮廓画得很好,没有填充,就像计划的一样)。在

Here is the image describing the problem

下面是右绘制的pixmap,它保存在TableModel的return之前:

pixmap

最终,有东西将返回的pixmap从QTableView单元格的左边界移动了3px。我没有在QtDesigner中为QTableView设置任何填充,也没有在以后的代码中更改它。我还尝试使用样式表手动将填充设置为零,但结果没有不同。在

有什么办法解决吗?非常感谢。在

以下是我的TableModel的示例:

class TableModel(QtCore.QAbstractTableModel):
def __init__(self, topology=None):
    super().__init__()
    ...
    # Hardcode cell size and path to rectangle image
    self.cell_width, self.cell_height = 21, 21
    self.fpath_red_rect = './path/to/red_rect.png'

def rowCount(self, parent=QtCore.QModelIndex()):
    return self.data.shape[0]

def columnCount(self, parent=QtCore.QModelIndex()):
    return self.data.shape[1]

def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
    ...

def size(self):
    return QtCore.QSize((self.columnCount() + 1) * self.cell_width,
                        (self.rowCount() + 1) * self.cell_height)

def data(self, index, role=QtCore.Qt.DisplayRole):
    if not index.isValid():
        return QtCore.QVariant()

    i = index.row()
    j = index.column()

    if role == QtCore.Qt.DisplayRole:
        if self.data[i, j] == 0:      # empty
            return ''
        elif self.data[i, j] == 1:    # cell with red rectangle
            # the text will be drawn on pixmap manually later
            return None
        else:
            return '{0}'.format(self.data[i, j])    # display default data

    if role == QtCore.Qt.DecorationRole:
        # Create pixmap, draw the rectangle on it and then draw text on top
        pixmap = QtGui.QPixmap(self.cell_width, self.cell_height)
        image = QtGui.QImage(self.fpath_red_rect).scaled(self.cell_width, self.cell_height)
        painter = QtGui.QPainter(pixmap)
        painter.drawImage(pixmap.rect().topLeft(), image)
        painter.drawText(pixmap.rect(), QtCore.Qt.AlignCenter, '{0}'.format(self.data[i, j]))
        painter.end()

        # If we save the pixmap to PNG image here (see the link above),
        # we get the expected 21 x 21 px image, with nice
        # and properly drawn rectangle and centered text.
        # But something goes wrong after returning

        return pixmap

    if role == QtCore.Qt.BackgroundRole:
        return QtGui.QBrush(self.getQtColor(self.data[i, j]))

    if role == QtCore.Qt.TextAlignmentRole:
        return QtCore.Qt.AlignCenter

    return QtCore.QVariant()

Tags: andtherectimageselfdatareturnif
1条回答
网友
1楼 · 发布于 2024-03-28 20:35:13

DecorationRole用于绘制图标,因此您可以观察到位移,在您的情况下,您不应该使用该角色,此外,绘制任务不应在模型中完成,因为他只需要提供数据,如果您想要修改绘图,一个更好的选择是使用委托,如下所示:

import sys

import numpy as np

from PyQt5 import QtCore, QtGui, QtWidgets

ValueRole = QtCore.Qt.UserRole + 1
max_val = 4

colors = [QtGui.QColor(*np.random.randint(255, size=3)) for i in range(max_val)]


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.data = np.random.randint(max_val, size=(10, 10))

    def rowCount(self, parent=QtCore.QModelIndex()):
        return self.data.shape[0]

    def columnCount(self, parent=QtCore.QModelIndex()):
        return self.data.shape[1]

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return QtCore.QVariant()

        i = index.row()
        j = index.column()
        val = self.data[i, j]

        if role == QtCore.Qt.DisplayRole:
            return str(val)

        elif role == QtCore.Qt.TextAlignmentRole:
            return QtCore.Qt.AlignCenter

        elif role == QtCore.Qt.BackgroundRole:
            return colors[val]

        if role == ValueRole:
            return val

        return QtCore.QVariant()

class Delegate(QtWidgets.QStyledItemDelegate):
    def paint(self, painter, option, index):
        QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
        if index.data(ValueRole) == 1:
            painter.save()
            pen = painter.pen()
            pen.setColor(QtCore.Qt.red)
            painter.setPen(pen)
            r = QtCore.QRect(option.rect)
            r.adjust(0, 0, -pen.width(), -pen.width())
            painter.drawRect(r)
            painter.restore()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QTableView()
    w.setItemDelegate(Delegate(w))
    model = TableModel()
    w.setModel(model)

    w.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
    w.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)

    for i in range(model.rowCount()):
        w.verticalHeader().resizeSection(i, 21)

    for j in range(model.columnCount()):
        w.horizontalHeader().resizeSection(j, 21)
    w.show()
    sys.exit(app.exec_())

enter image description here

相关问题 更多 >