简体   繁体   中英

Adding tools to Scribble app with PYQT4

I am trying to write an app which works as MS Paint or other simple graphics editor. My goal is to provide such funcionality as: different tools( drawing lines, figures etc.), posibility to change colors, width, size and undo/redo function. I thought that the easiest way to do it was to create separete classes for drawing and viewing objects. Unfortunetly, it is not working properly. Here`s my code:

import sys
from PyQt4 import QtGui, QtCore

class Example(QtGui.QWidget):    
    def __init__(self):
        super(Example, self).__init__()
        self.update()

        self.view = View(self)
        self.action = Action(self.view.scene)

        self.UI()

    def UI(self):
        self.setGeometry(300,300,300,300)

        self.setWindowTitle('Pen styles')
        self.undo = QtGui.QPushButton("undo", self)
        self.undo.clicked.connect(self.action.undoStack.undo)
        self.redo = QtGui.QPushButton("redo", self)
        self.redo.clicked.connect(self.action.undoStack.redo)
        self.redo.move(0,50)
        self.tool = QtGui.QPushButton("tool", self)
        self.tool.setCheckable(True)
        self.tool.clicked[bool].connect(self.new)
        self.tool.move(0,100)

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.view)
        self.setLayout(layout)

        self.show()

    def new(self):    
        pass


class Action(QtGui.QGraphicsScene):    
    def __init__(self, scene):    
        QtGui.QGraphicsScene.__init__(self)

        self.undoStack = QtGui.QUndoStack(self)

        self.scene = scene
        self.scene.addLine(0,0,150,150)

        self.undoStack = QtGui.QUndoStack(self)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.start = event.pos()
            self.scene.addLine(0,0,150,250)

    def mouseReleaseEvent(self, event):
        start = QtCore.QPointF(self.mapToScene(self.start))
        end = QtCore.QPointF(self.mapToScene(event.pos()))
        self.drawing(start, end)

    def drawing(self, start, end):
        self.line = QtGui.QGraphicsLineItem(QtCore.QLineF(start, end))
        self.line.setPen(QtGui.QPen(QtCore.Qt.blue,3,
                QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))

        self.scene.addLine(0,0,150,300)
        command = Draw(self.line, self.scene)
        self.undoStack.push(command)


class Draw(QtGui.QUndoCommand):
    def __init__(self, line, scene):
        QtGui.QUndoCommand.__init__(self)

        self.line = line
        self.scene = scene

    def redo(self):
        self.scene.addItem(self.line)

    def undo(self):
        self.scene.removeItem(self.line)


class View(QtGui.QGraphicsView):    
    def __init__(self, parent):    
        QtGui.QGraphicsView.__init__(self, parent)    

        self.scene = QtGui.QGraphicsScene()
        self.action = Action(self.scene)
        self.setScene(self.scene)
        self.setSceneRect(QtCore.QRectF(self.viewport().rect()))


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

My problem is that i cannot draw anything using my mouse. If class Action and View are combined everything is working fine, but when I put them away nothing happens(no error as well). The reason I did this separation is that I simple want to add another classes with other functionality (drawing elipses, rects...) and swap them with Action class. I added line to the scene (in Action init ) and it`s being painted corectly, but the MouseEvents dont work at all.The button "tool" was made for changing the drawing tool.

This way, in my opinion, is the best way to achive ability to scribble with different tools on the same canvas(scene). My way aint good so I am asking for help. What can I do fix this code, so it works as I want? Where are the mistakes? or maybe the whole approach is wrong and it should be done another way? I use PYQT 4 and Python 3.4 .

Your current code has two instances of a QGraphicsScene created inside View.__init__ . One is a standard QGraphicsScene and the other is your subclass Action . But your view can only be attached to one scene, so one of these is redundant and not functioning correctly. You have attached it to the QGraphicsScene , so the Action object is the one not working.

Instead, you should kill off the plain boring QGraphicsScene , and only instantiate the Action class. Use the instantiated Action object in the call to view.setScene() . Similarly, in the Action class, there is no need to pass in another scene. Just use itself (so replace all instances of self.scene with self in the Action class)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM