我的PyQt5应用程序在进入“window.show()时崩溃”

2024-09-30 22:10:35 发布

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

我是PYQT5的新手,我尝试用C++编写一些代码,将其用Qt翻译成PYQT5: 这是一个绘图应用程序,如图所示:http://www.newthinktank.com/2018/07/qt-tutorial-5-paint-app/

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




class ScribbleArea(QtWidgets.QWidget):
    def __init__(self, parent = 0):
        super().__init__()
        self.parent = parent
        self.modified = False
        self.scribbling = False
        self.myPenColor = QtCore.Qt.blue
        self.myPenWidth = 1
        self.image = None
        self.lastPoint = None
        self.setAttribute(QtCore.Qt.WA_StaticContents)


    def openImage(self, fileName):
        loadedImage = QtGui.QImage(fileName)
        if not loadedImage:
            return False
        newSize = loadedImage.size().expandedTo(self.size())
        self.resizeImage(loadedImage, newSize)
        self.image = loadedImage
        self.modified = False
        self.update()
        return True


    def saveImage(self, fileName, fileFormat):
        visibleImage = self.image
        self.resizeImage(visibleImage, self.size())
        if visibleImage.save(fileName, fileFormat):
            self.modified = False
            return True
        else:
            return False


    def clearImage(self):
        self.image.fill(QtGui.QColor(255, 255, 255))
        self.modified = True
        self.update()



    def print(self):
        try:
            from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
        except ImportError as e:
            print("not print support")
        else:
            printer = QPrinter(QPrinter.HighResolution)
            printDialog = QPrintDialog(printer, self)
            if printDialog.exec_() == QtWidgets.QDialog.Accepted:
                painter = QtGui.QPainter(printer)
                rect = painter.viewport()
                size = self.image.size()
                size.scale(rect.size(), QtCore.Qt.KeepAspectRatio)
                painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
                painter.setWindow(self.image.rect())
                painter.drawImage(0, 0, self.image)


    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.lastPoint = event.pos()
            self.scribbling = True


    def mouseMoveEvent(self, event):
        if (event.buttons() & QtCore.Qt.LeftButton) and self.scribbling:
            self.drawLineTo(event.pos())


    def mouseReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton and self.scribbling:
            self.drawLineTo(event.pos())
            self.scribbling = False


    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        dirtyRect = event.rect()
        painter.drawImage(dirtyRect, self.image, dirtyRect)


    def resizeEvent(self, event):
        if self.width() > self.image.width() or self.height() > self.image.height():
            newWidth = max(self.width() + 128, self.width())
            newHeight = max(self.height() + 128, self.height())
            self.resizeImage(self.image, QtCore.QSize(newWidth, newHeight))
            self.update()
        QtWidgets.QWidget.resizeEvent(self, event)


    def drawLineTo(self, endPoint):
        painter = QtGui.QPainter(self.image)
        painter.setPen(QtGui.QPen(self.myPenColor, self.myPenWidth, QtCore.Qt.SolidLine,
                                  QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
        painter.drawLine(self.lastPoint, endPoint)
        self.modified = True
        rad = (self.myPenWidth / 2) + 2
        self.update(QtCore.QRect(self.lastPoint, endPoint).normalize().adjusted(-rad, -rad, +rad, +rad))
        self.lastPoint = endPoint



    def resizeImage(self, image, newSize):
        if image.size() == newSize:
            return
        newImage = QtGui.QImage(newSize, QtGui.QImage.Format_RGB32)
        newImage.fill(QtGui.QColor(255, 255, 255))
        painter = QtGui.QPainter(newImage)
        painter.drawImage(QtCore.QPoint(0, 0), image)
        image = newImage                          #
        return image                              #


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.scribbleArea = ScribbleArea()
        self.saveAsMenu = None
        self.fileMenu = None
        self.optionMenu = None
        self.helpMenu = None
        self.openAct = None
        self.saveAsActs = []
        self.penColorAct = None
        self.penWidthAct = None
        self.printAct = None
        self.exitAct = None
        self.clearScreenAct = None
        self.aboutAct = None
        self.aboutQtAct = None
        self.setCentralWidget(self.scribbleArea)
        self.createActions()
        self.createMenus()
        self.setWindowTitle(self.tr("Scribble"))
        self.resize(500, 500)
        self.createMenus()
        self.createActions()

    def closeEvent(self, event):
        if self.maybeSave():
            event.accept()
        else:
            event.ignore()


    def open(self):
        if self.maybeSave():
            fileName,_filter = QtWidgets.QFileDialog.getOpenFileName(self, self.tr("Open File"), QtCore.QDir.currentPath())
            if fileName:
                self.scribbleArea.openImage(fileName)


    def save(self):
        action = QtWidgets.QAction(self.sender())   #action = self.sender()
        fileFormat = action.data().toByteArray()
        self.saveFile(fileFormat)


    def close(self):
        pass


    def penColor(self):
        newColor = QtWidgets.QColorDialog.getColor(self.scribbleArea.myPenColor)   #.penColor()
        if newColor.isValid():
            self.scribbleArea.myPenColor = newColor


    def penWidth(self):
        newWidth, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Scribble"), self.tr("Select pen width: "),
                                                 self.scribbleArea.myPenWidth, 1, 50, 1)
        if ok:
            self.scribbleArea.myPenWidth = newWidth



    def about(self):
        QtWidgets.QMessageBox.about(self, self.tr("About scribble"), self.tr("<p>The <b>Scribble</b> example is awesome</p>"))


    def createActions(self):
        self.openAct = QtWidgets.QAction(self.tr("Open"), self)
        self.openAct.setShortcuts(QtGui.QKeySequence.Open)
        self.openAct.triggered.connect(self.open)

        for format in QtGui.QImageWriter.supportedImageFormats():
            text = self.tr("{}...").format(str(format).upper())
            action = QtWidgets.QAction(text, self)
            action.setData(format)
            action.triggered.connect(self.save)
            self.saveAsActs.append(action)
        self.printAct = QtWidgets.QAction(self.tr("Print"), self)
        self.printAct.triggered.connect(self.scribbleArea.print) #
        self.exitAct = QtWidgets.QAction(self.tr("Exit"), self)
        self.exitAct.setShortcuts(QtGui.QKeySequence.Quit)
        self.exitAct.triggered.connect(self.close)
        self.penColorAct = QtWidgets.QAction(self.tr("Pen color..."), self)
        self.penColorAct.triggered.connect(self.penColor)
        self.penWidthAct = QtWidgets.QAction(self.tr("Pen width..."), self)
        self.penWidthAct.triggered.connect(self.penWidth)
        self.clearScreenAct = QtWidgets.QAction(self.tr("Clear Screen..."), self)
        self.clearScreenAct.setShortcut(self.tr("Ctrl+L"))
        self.clearScreenAct.triggered.connect(self.scribbleArea.clearImage) #
        self.aboutAct = QtWidgets.QAction(self.tr("About..."), self)
        self.aboutAct.triggered.connect(self.about)
        self.aboutQtAct = QtWidgets.QAction(self.tr("About Qt ..."), self)
        self.aboutQtAct.triggered.connect(QtWidgets.qApp.aboutQt)


    def createMenus(self):
        self.saveAsMenu = QtWidgets.QMenu(self.tr("Save as"), self)
        for action in self.saveAsActs:
            self.saveAsMenu.addAction(action)
        self.fileMenu = QtWidgets.QMenu(self.tr("File"), self)
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addMenu(self.saveAsMenu)
        self.fileMenu.addAction(self.printAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)
        self.optionMenu = QtWidgets.QMenu(self.tr("Options"), self)
        self.optionMenu.addAction(self.penColorAct)
        self.optionMenu.addAction(self.penWidthAct)
        self.optionMenu.addSeparator()
        self.optionMenu.addAction(self.clearScreenAct)

        self.helpMenu = QtWidgets.QMenu(self.tr("Help"), self)
        self.helpMenu.addAction(self.aboutAct)
        self.helpMenu.addAction(self.aboutQtAct)

        self.menuBar().addMenu(self.fileMenu)
        self.menuBar().addMenu(self.optionMenu)
        self.menuBar().addMenu(self.helpMenu)


    def maybeSave(self):
        if self.scribbleArea.modified:
            ret = QtWidgets.QMessageBox.warning(self, self.tr("Scribble"), self.tr("The image has been modified. \n"
                                                                                   "Do you want to save the changes?"),
                            QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard | QtWidgets.QMessageBox.Cancel)
            if ret == QtWidgets.QMessageBox.Save:
                return self.saveFile("png")
            elif ret == QtWidgets.QMessageBox.Cancel:
                return False
        return True


    def saveFile(self, fileFormat):
        initialPath = QtCore.QDir.currentPath() + "/untitled." + fileFormat
        fileName = QtWidgets.QFileDialog.getSaveFileName(
            self,
            self.tr("Save As"),
            initialPath,
            self.tr("{} Files (*.{});;All Files (*)").format(fileFormat.upper(), fileFormat))

        if not fileName:
            return False
        else:
            return self.scribbleArea.saveImage(fileName, fileFormat.constData())



app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

我尝试过调试,但很明显它在“window.show()”时崩溃了。正如我所说,我是新来的,我不擅长自己调试它


Tags: imageselfnoneeventreturnifdeffilename
1条回答
网友
1楼 · 发布于 2024-09-30 22:10:35

如果在提示符/终端中运行程序,您将清楚地看到以下回溯:

Traceback (most recent call last):
  File "paintchazz.py", line 93, in resizeEvent
    if self.width() > self.image.width() or self.height() > self.image.height():
AttributeError: 'NoneType' object has no attribute 'width'

这是因为self.image仍然是None,并且None没有属性

必须在代码中添加检查,以确保已设置属性:

    def paintEvent(self, event):
        if self.image:
            painter = QtGui.QPainter(self)
            dirtyRect = event.rect()
            painter.drawImage(dirtyRect, self.image, dirtyRect)


    def resizeEvent(self, event):
        if self.image:
            if self.width() > self.image.width() or self.height() > self.image.height():
                newWidth = max(self.width() + 128, self.width())
                newHeight = max(self.height() + 128, self.height())
                self.resizeImage(self.image, QtCore.QSize(newWidth, newHeight))
                self.update()
        QtWidgets.QWidget.resizeEvent(self, event)

注意drawLineTo()函数中还有一个语法错误,正如您使用的normalize(),但它实际上是^{}

相关问题 更多 >