Краш приложения при использовании 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 шт):
Попробуйте делать проверку того, что устройство для рисования (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()
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_())

