Как при рисование (с помощью мыши) сделать действия "undo" и "redo" PyQt QPainter
Я хочу при рисование сделать undo/redo. Допустим я нарисовал несколько линий и захотел последнюю отменить, а затем вернуть, как это можно реализовать к примеру клавишами Ctrl+Z/Ctrl+Y?
Вот код
import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QMouseEvent, QPen, QPixmap, QPainterPath
from PyQt5.QtCore import Qt, QPoint
class Drawing(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.drawingPath = None
self.resize(500, 500)
self.image = QPixmap(500, 500)
self.image.fill(Qt.white)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(QPoint(), self.image)
if self.drawingPath:
painter.setPen(QPen(QColor(0, 0, 0), 10, Qt.SolidLine))
painter.drawPath(self.drawingPath)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drawingPath = QPainterPath()
self.drawingPath.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
if event.buttons() and Qt.LeftButton and self.drawingPath:
self.drawingPath.lineTo(event.pos())
self.update()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.drawingPath:
painter = QPainter(self.image)
painter.setPen(QPen(QColor(0, 0, 0), 10, Qt.SolidLine))
painter.drawPath(self.drawingPath)
self.drawingPath = None
self.update()
class Main(QWidget):
def __init__(self):
super().__init__()
self.drawing = Drawing(self)
self.resize(500, 500)
self.show()
self.drawing.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Класс
QUndoCommand- это базовый класс всех команд, хранящихся вQUndoStack.
Класс
QUndoStack- это стек объектовQUndoCommand.
Вы можете также пользоваться клавишами Ctrl+Z / Ctrl+Y
import sys
from PyQt5.Qt import *
class UndoCommand(QUndoCommand):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.mPrevImage = parent.image.copy()
self.mCurrImage = parent.image.copy()
def undo(self):
self.mCurrImage = self.parent.image.copy()
self.parent.image = self.mPrevImage
self.parent.update()
def redo(self):
self.parent.image = self.mCurrImage
self.parent.update()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.mUndoStack = QUndoStack(self)
self.mUndoStack.setUndoLimit(20)
self.mUndoStack.canUndoChanged.connect(self.can_undo_changed)
self.mUndoStack.canRedoChanged.connect(self.can_redo_changed)
self.actionUndo = self.menuBar().addAction("Undo")
self.actionUndo.triggered.connect(self.mUndoStack.undo)
self.actionRedo = self.menuBar().addAction("Redo")
self.actionRedo.triggered.connect(self.mUndoStack.redo)
self.can_undo_changed(self.mUndoStack.canUndo())
self.can_redo_changed(self.mUndoStack.canRedo())
self.image = QPixmap(500, 500)
self.image.fill(Qt.darkGreen)
self.is_pressed = False
self.drawingPath = None
def can_undo_changed(self, enabled):
self.actionUndo.setEnabled(enabled)
def can_redo_changed(self, enabled):
self.actionRedo.setEnabled(enabled)
def make_undo_command(self):
self.mUndoStack.push(UndoCommand(self))
def draw(self, parent):
painter = QPainter(parent)
if self.drawingPath:
painter.setPen(QPen(QColor(0, 0, 0), 5, Qt.SolidLine))
painter.drawPath(self.drawingPath)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(QPoint(), self.image)
if self.is_pressed:
self.draw(self)
def mousePressEvent(self, event):
self.is_pressed = True
if event.button() == Qt.LeftButton:
self.drawingPath = QPainterPath()
self.drawingPath.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
if event.buttons() and Qt.LeftButton and self.drawingPath:
self.drawingPath.lineTo(event.pos())
self.update()
def mouseReleaseEvent(self, event):
self.is_pressed = False
self.make_undo_command()
self.draw(self.image)
self.update()
def keyPressEvent(self, event):
if event.key() == Qt.Key_Z and event.modifiers() == Qt.ControlModifier:
self.mUndoStack.undo()
elif event.key() == Qt.Key_Y and event.modifiers() == Qt.ControlModifier:
self.mUndoStack.redo()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.resize(500, 500)
w.show()
sys.exit(app.exec_())
