Краш приложения при использовании QPainter при скруглении картинки

Мне нужно было заполнить один столбец QTableWidget скругленными картинками.

Из разных источников получилось собрать подходящее решение, с помощью QPainter. Всё работает, но код запускается только в режиме дебага при проходе каждой строки, иначе крашит с ошибкой по типу

Process finished with exit code -1073741819 (0xC0000005).

Среда разработки PyCharm, Python 3.7. При попытке добавления больше 2 картинок также крашит.

Полный код:

import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class Table(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("QTableWidget example")

        self.resize(1000, 900)
        layout = QHBoxLayout()
        table = QTableWidget(3, 3)

        table.setHorizontalHeaderLabels(['image 1', 'image 2', 'image 3'])

        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        table.setIconSize(QSize(48, 48))
        table.setRowHeight(0, 58)

        for i in range(3):
            table.setColumnWidth(i, 58)
        for i in range(3):
            table.setRowHeight(i, 58)

        img = QtGui.QPixmap('name.png') # заполнение одной картинкой

        for k in range(2):
        
            i = k / 3
            j = k % 3

            radius = 96
            rounded = QtGui.QPixmap(img.size())
            rounded.fill(QtGui.QColor("transparent"))

            painter = QtGui.QPainter(rounded)
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            painter.setBrush(QtGui.QBrush(img))
            painter.setPen(QtCore.Qt.NoPen)
            painter.drawRoundedRect(img.rect(), radius, radius)

            item = QTableWidgetItem()
            item.setFlags(Qt.ItemIsEnabled)
            icon = QIcon(rounded)
            item.setIcon(QIcon(icon))

            table.setItem(i, j, item)

        layout.addWidget(table)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    example = Table()
    example.show()
    sys.exit(app.exec_())

Краши происходят в этих строчках:

painter = QtGui.QPainter(rounded)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(QtGui.QBrush(img))
painter.setPen(QtCore.Qt.NoPen)
painter.drawRoundedRect(img.rect(), radius, radius)

Код работает, вот результат:

введите сюда описание изображения

Но из-за чего он так крашится? Возможно есть другое более правильное решение.


Ответы (2 шт):

Автор решения: Alexander Chernin

Попробуйте делать проверку того, что устройство для рисования (QPaintDevice) валидно.

Либо так:

if !rounded.isNull():
    painter = QtGui.QPainter(rounded)
    ...
    table.setItem(i, j, item)

Или так (док):

painter = QtGui.QPainter()
if painter.begin(rounded):
    painter.setRenderHint(QtGui.QPainter.Antialiasing)
    ...
    table.setItem(i, j, item)
    painter.end()
→ Ссылка
Автор решения: S. Nick

bool QPainter::end()

Заканчивает painting. Все ресурсы, использованные во время рисования, высвобождаются. Обычно вам не нужно вызывать это, поскольку он вызывается деструктором.
Возвращает true, если рисовальщик больше не активен; в противном случае возвращает false.

import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class Table(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("QTableWidget example")

        self.resize(1000, 900)
        layout = QHBoxLayout(self)
        
        label = QLabel()
        layout.addWidget(label)
        
        self.table = QTableWidget(3, 3)

        self.table.setHorizontalHeaderLabels(['image 1', 'image 2', 'image 3'])

        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setIconSize(QSize(48, 48))
        self.table.setRowHeight(0, 58)

        for i in range(3):
            self.table.setColumnWidth(i, 58)
        for i in range(3):
            self.table.setRowHeight(i, 58)

        for k in range(9):
            i = k / 3
            j = k % 3

            # original
            pixmap = QtGui.QPixmap('lena.jpg')
            radius = 256  
            
            # создаем пустое растровое изображение того же размера, что и исходное 
            rounded = QtGui.QPixmap(pixmap.size())
            rounded.fill(QtGui.QColor("transparent"))
            
            # draw нарисуйте закругленный прямоугольник на новом растровом изображении, 
            # используя исходное растровое изображение в качестве кисти
            painter = QtGui.QPainter(rounded)

            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            painter.setBrush(QtGui.QBrush(pixmap))
            painter.setPen(QtCore.Qt.NoPen)
            painter.drawRoundedRect(pixmap.rect(), radius, radius)
            
            painter.end()                                          # <----
            
            label.setPixmap(rounded)
            
            item = QTableWidgetItem()
            item.setFlags(Qt.ItemIsEnabled)
            icon = QIcon(rounded)
            item.setIcon(QIcon(icon))
            self.table.setItem(i, j, item)

        layout.addWidget(self.table)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    example = Table()
    example.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка