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)