使用 PYQT4 向 Scribble 应用程序添加工具
Adding tools to Scribble app with PYQT4
我正在尝试编写一个用作 MS Paint 或其他简单图形编辑器的应用程序。我的目标是提供这样的功能:不同的工具(画线、图形等)、改变颜色、宽度、大小和 undo/redo 功能的可能性。我认为最简单的方法是创建单独的 classes 来绘制和查看对象。不幸的是,它不能正常工作。这是我的代码:
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()
我的问题是我无法使用鼠标绘制任何东西。如果 class Action 和 View 组合在一起,一切正常,但是当我把它们收起来时什么也没有发生(也没有错误)。我进行这种分离的原因是我只是想添加另一个具有其他功能(绘制椭圆、矩形...)的 classes 并将它们与 Action class 交换。我在场景中添加了线条(在 Action init 中)并且它被正确地绘制了,但是 MouseEvents 在 all.The 按钮上不起作用 "tool" 是为了改变绘图工具。
在我看来,这种方式是实现在同一 canvas(场景) 上使用不同工具涂鸦的最佳方式。我的方法不好,所以我寻求帮助。我该怎么做才能修复此代码,使其按我的意愿工作?错误在哪里?或者也许整个方法是错误的,应该以另一种方式完成?我使用 PYQT 4 和 Python 3.4 .
您当前的代码在 View.__init__
中创建了两个 QGraphicsScene
实例。一个是标准的QGraphicsScene
,另一个是你的subclass Action
。但是您的视图只能附加到一个场景,因此其中一个是多余的并且无法正常运行。您已将其附加到 QGraphicsScene
,因此 Action
对象无效。
相反,您应该消除无聊的 QGraphicsScene
,只实例化 Action
class。在对 view.setScene()
的调用中使用实例化的 Action
对象。同样,在Action
class中,也不需要再传入另一个场景。只需使用它自己(因此在 Action
class 中将 self.scene
的所有实例替换为 self
)
我正在尝试编写一个用作 MS Paint 或其他简单图形编辑器的应用程序。我的目标是提供这样的功能:不同的工具(画线、图形等)、改变颜色、宽度、大小和 undo/redo 功能的可能性。我认为最简单的方法是创建单独的 classes 来绘制和查看对象。不幸的是,它不能正常工作。这是我的代码:
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()
我的问题是我无法使用鼠标绘制任何东西。如果 class Action 和 View 组合在一起,一切正常,但是当我把它们收起来时什么也没有发生(也没有错误)。我进行这种分离的原因是我只是想添加另一个具有其他功能(绘制椭圆、矩形...)的 classes 并将它们与 Action class 交换。我在场景中添加了线条(在 Action init 中)并且它被正确地绘制了,但是 MouseEvents 在 all.The 按钮上不起作用 "tool" 是为了改变绘图工具。
在我看来,这种方式是实现在同一 canvas(场景) 上使用不同工具涂鸦的最佳方式。我的方法不好,所以我寻求帮助。我该怎么做才能修复此代码,使其按我的意愿工作?错误在哪里?或者也许整个方法是错误的,应该以另一种方式完成?我使用 PYQT 4 和 Python 3.4 .
您当前的代码在 View.__init__
中创建了两个 QGraphicsScene
实例。一个是标准的QGraphicsScene
,另一个是你的subclass Action
。但是您的视图只能附加到一个场景,因此其中一个是多余的并且无法正常运行。您已将其附加到 QGraphicsScene
,因此 Action
对象无效。
相反,您应该消除无聊的 QGraphicsScene
,只实例化 Action
class。在对 view.setScene()
的调用中使用实例化的 Action
对象。同样,在Action
class中,也不需要再传入另一个场景。只需使用它自己(因此在 Action
class 中将 self.scene
的所有实例替换为 self
)