Программа завершается без предупреждения [PyQt5]

#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 не будет принимать эти параметры; в качестве примечания учтите, что если пользователь не принимает диалоговое окно (потому что, возможно, он / она нажалнеправильная кнопка), вы не должны устанавливать эти значения и продолжать запрашивать другие параметры.

Наконец, два предложения.

  1. рисование в главном окне не должно происходить, если это действительно не требуется; это связано с тем, что QMainWindow представляет собой особый вид QWidget и имеет определенный набор функций, которые потенциально могут создавать проблемы с пользовательским рисованием; вместо этого следует предпочесть рисование на выделенном QWidget. Это можно сделать, установив фильтр событий для этого виджета (возможно, центрального виджета) и paint при обнаружении события paint, или создав подкласс QWidget, реализовать его собственный paintEvent и добавить этот виджет в главное окно.
  2. (это довольно тривиально, но может немного упростить ваш код) вам не нужно вручную вызывать begin и end в экземпляре QPainter, так как вы можете просто создать экземпляр с помощью устройства рисования в конструкторе ( qp = QtGui.QPainter(self) ) и игнорировать окончание, поскольку painter будет автоматически закрыт и корректно уничтожен, как толькопри возврате функции paintEvent.