#python #user-interface #pyqt5
#python #пользовательский интерфейс #pyqt5
Вопрос:
Я пишу программу, похожую на Paint, на PyQt5. Я столкнулся с проблемой при написании pen tool.
Моя идея: если currentMode == 1 (клавиша penMode) и нажата мышь — тогда программа создает круг со значением ширины == self.width и цветом == self.color. Но моя программа завершается с кодом выхода -1073740791 (0xC0000409). Я не являюсь носителем английского языка и не могу найти способ решить эту проблему.
Мой код (основная часть):
class TPaintWorker(QtWidgets.QMainWindow, TPaintGUI):
def __init__(self):
super().__init__()
self.setupUi(self)
self.currentMode = 0
self.width = 0
self.drawX = 0
self.drawY = 0
self.endX = 0
self.endY = 0
self.doPaint = False
self.color = QtGui.QColor(255, 255, 255)
self.penMode.clicked.connect(self.penDrawerActivate)
self.polygonMode.clicked.connect(self.polygonDrawerActivate)
self.circleMode.clicked.connect(self.circleDrawerActivate)
self.eraserMode.clicked.connect(self.eraserActivate)
self.saveImage.clicked.connect(self.saveProcess)
self.loadImage.clicked.connect(self.loadProcess)
def mousePressEvent(self, event):
if self.currentMode:
self.drawX = event.x
self.drawY = event.y
self.paintPrepare()
self.update()
def paintPrepare(self):
self.doPaint = True
self.repaint()
def paintEvent(self, event):
if self.doPaint:
qp = QtGui.QPainter()
qp.begin(self)
if self.currentMode == 1:
self.penDrawer(qp)
print("im out")
qp.end()
def penDrawerActivate(self):
self.currentMode = 1
self.width = QtWidgets.QInputDialog.getInt(self, "Input width value", "Width value:", 5, 1, 100, 1)
self.color = QtWidgets.QColorDialog.getColor(QtGui.QColor(255, 255, 255))
def penDrawer(self, qp):
print("im in")
self.pen = QtGui.QPen(self.color)
qp.setPen(self.pen)
qp.drawEllipse(self.drawX, self.drawY, self.width, self.width)
def polygonDrawerActivate(self):
self.currentMode = 2
self.dots = QtWidgets.QInputDialog.getInt(self, "Input number of dots", "Number of dots:", 4, 3, 25, 1)
self.width = QtWidgets.QInputDialog.getInt(self, "Input width value", "Width value:", 5, 1, 100, 1)
self.color = QtWidgets.QColorDialog.getColor(QtGui.QColor(255, 255, 255))
def circleDrawerActivate(self):
self.currentMode = 3
self.radius = QtWidgets.QInputDialog.getInt(self, "Input radius of circle", "Radius:", 50, 5, 200, 1)
self.width = QtWidgets.QInputDialog.getInt(self, "Input width value", "Width value:", 5, 1, 100, 1)
self.color = QtWidgets.QColorDialog.getColor(QtGui.QColor(255, 255, 255))
def eraserActivate(self):
self.currentMode = 4
self.width = QtWidgets.QInputDialog.getInt(self, "Input width of eraser", "Width value:", 50, 5, 200, 1)
def loadProcess(self):
loadPath, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Load image", "C:/", "PNG (*.png);;JPEG (*.jpg)")
if loadPath:
pixmap = QtGui.QPixmap(loadPath)
self.canvas.setPixmap(pixmap)
def saveProcess(self):
savePath, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save image", "C:/", "PNG (*.png);;JPEG (*.jpg)")
if savePath:
image = QtGui.QImage(self.canvas.pixmap())
image.save(savePath)
Комментарии:
1.
print("im in")
иprint("im out)"
— мои материалы для отладки и поиска проблемной области
Ответ №1:
Прежде всего, я предлагаю вам проверить вывод ошибок, запустив вашу программу в командной строке / командной строке (обратите внимание, что IDE иногда не могут полностью отображать полную обратную трассировку): вам, вероятно, пришлось бы отслеживать свои проблемы самостоятельно.
Первая проблема заключается в том, что вы не получаете координаты в mousePressEvent()
; в Qt доступ к почти всем свойствам осуществляется через вызываемые объекты (за исключением некоторых очень специфических исключений, таких как свойства подклассов QStyleOption).
Результатом является то, что drawX
и drawY
на самом деле являются не координатами, а ссылками на event.x
и event.y
функции соответственно.
Затем все статические методы QInputDialog возвращают кортеж, состоящий из (value, accepted)
: второе значение указывает, было ли принято диалоговое окно или нет (если пользователь нажал «Отмена» Escили закрыл окно).
Поскольку вы устанавливаете все значения в полный кортеж, Qt, очевидно, будет аварийно завершаться всякий раз, когда вы пытаетесь использовать эти значения для рисования, поскольку связанная функция QPainter не будет принимать эти параметры; в качестве примечания учтите, что если пользователь не принимает диалоговое окно (потому что, возможно, он / она нажалнеправильная кнопка), вы не должны устанавливать эти значения и продолжать запрашивать другие параметры.
Наконец, два предложения.
- рисование в главном окне не должно происходить, если это действительно не требуется; это связано с тем, что QMainWindow представляет собой особый вид QWidget и имеет определенный набор функций, которые потенциально могут создавать проблемы с пользовательским рисованием; вместо этого следует предпочесть рисование на выделенном QWidget. Это можно сделать, установив фильтр событий для этого виджета (возможно, центрального виджета) и paint при обнаружении события paint, или создав подкласс QWidget, реализовать его собственный
paintEvent
и добавить этот виджет в главное окно. - (это довольно тривиально, но может немного упростить ваш код) вам не нужно вручную вызывать
begin
иend
в экземпляре QPainter, так как вы можете просто создать экземпляр с помощью устройства рисования в конструкторе (qp = QtGui.QPainter(self)
) и игнорировать окончание, поскольку painter будет автоматически закрыт и корректно уничтожен, как толькопри возврате функции paintEvent.