QUndoCommand的使用——实现undo/redo

实现思路

1、简要介绍undo、redo的原理
2、在Qt中实现undo、redo的要点
3、在Qt中实现undo、redo的实例

例子实现效果如下:
在这里插入图片描述

可以看到数字的变化为0、64、12、16、60,当我们使用undo的时候,数字从60一直变回到0,此时我们再使用redo,数字又从0变到60

1、简要介绍undo、redo的原理

有一个堆,用于存放每一次的操作(当然也可以是数据),每次操作都把当前的操作(数据)push进这个堆,因为堆是先进后出的,也就是后面进的先出来,也就符合了我们undo、redo的使用规律。

2、在Qt中实现undo、redo的要点

Qt中有一个“QUndoStack”对应于上述所说的堆,推进堆内的东西是一个command的,也就是一个需求,在Qt中有个类“QUndoCommand”,我们只要实现其内部的redo、undo,并在每次操作过后创建对应的command并将其推入“QUndoStack”中,就可以实现redo、undo的效果

3、在Qt中实现undo、redo的实例

# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
import sys

import random
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QPushButton, QWidget, QUndoCommand, \
    QUndoStack, QSlider, QLabel


class SliderCommand(QUndoCommand):

    def __init__(self, sld, preValue, curValue, parent=None):
        super(SliderCommand, self).__init__(parent)
        self.sld = sld
        self.preValue = preValue
        self.curValue = curValue
        self.setText("文字redo/undo")

    def redo(self):
        self.sld.setValue(self.curValue)

    def undo(self):
        self.sld.setValue(self.preValue)


class ComplexDrag(QWidget):

    def __init__(self):
        super(ComplexDrag, self).__init__()
        self.undoInit()
        self.initUI()

    def undoInit(self):
        self.undoStack = QUndoStack(self)
        self.undoStack.setUndoLimit(50)
        undoAction = self.undoStack.createUndoAction(self, "Undo")
        undoAction.setShortcut("Ctrl+Z")
        redoAction = self.undoStack.createRedoAction(self, "Redo")
        redoAction.setShortcut("Ctrl+Shift+Z")
        self.addAction(undoAction)
        self.addAction(redoAction)

    def initUI(self):
        verLayout = QVBoxLayout()
        horLayout = QHBoxLayout()
        self.actionBtn = QPushButton("doAction")
        self.actionBtn.clicked.connect(self.doActionFunc)
        self.lable = QLabel()
        self.lable.setText("当前值为:0")
        self.sld = QSlider(Qt.Horizontal, self)
        self.sld.setFocusPolicy(Qt.NoFocus)
        self.sld.setGeometry(30, 40, 100, 30)
        self.sld.valueChanged[int].connect(self.onValueChanged)
        verLayout.addWidget(self.sld)
        verLayout.addWidget(self.lable)
        horLayout.addWidget(self.actionBtn)
        verLayout.addLayout(horLayout)
        self.setLayout(verLayout)
        self.setWindowTitle("Redo and Undo")

    def doActionFunc(self):
        curValue = random.randint(0, 100)
        command = SliderCommand(self.sld, self.sld.value(), curValue)
        self.undoStack.push(command)

    def onValueChanged(self, num):
        self.lable.setText("当前值为:" + str(num))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ComplexDrag()
    ex.show()
    app.exec_()

主要分析:
1、首先创建一个堆 self.undoStack = QUndoStack(self)
2、为这个堆创建undo、redo对应的action以及对应的快捷键,详细看undoInit方法
3、我们通过一个按钮改变slider的值
4、点击这个按钮就是一个操作,我们为这个操作创建command即SliderCommand
5、在SliderCommand中实现对应的redo、undo方法

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Eclipse 中,可以使用 `org.eclipse.ui.actions.ActionFactory.UNDO` 和 `org.eclipse.ui.actions.ActionFactory.REDO` 来创建 UndoRedo 动作。然后,将这些动作关联到菜单栏 Edit 中的 UndoRedo 菜单项。 要在 `ViewPart` 中实现 Undo/Redo,您需要遵循以下步骤: 1. 在 `ViewPart` 类中添加以下字段: ```java private IUndoContext undoContext; private IUndoableOperation undoOperation; private IAction undoAction; private IAction redoAction; ``` 2. 在 `createPartControl` 方法中初始化这些字段: ```java public void createPartControl(Composite parent) { // 创建 Undo/Redo 上下文 undoContext = new ObjectUndoContext(new Object()); // 创建 Undo/Redo 动作 undoAction = ActionFactory.UNDO.create(getSite().getWorkbenchWindow()); undoAction.setText("Undo"); undoAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages() .getImageDescriptor(ISharedImages.IMG_TOOL_UNDO)); undoAction.setEnabled(false); redoAction = ActionFactory.REDO.create(getSite().getWorkbenchWindow()); redoAction.setText("Redo"); redoAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages() .getImageDescriptor(ISharedImages.IMG_TOOL_REDO)); redoAction.setEnabled(false); // 将 Undo/Redo 动作添加到菜单栏 Edit 中 IMenuManager menuMgr = getViewSite().getActionBars().getMenuManager(); menuMgr.add(new Separator()); menuMgr.add(undoAction); menuMgr.add(redoAction); } ``` 3. 在 `createPartControl` 方法中为 Undo/Redo 动作添加处理程序: ```java public void createPartControl(Composite parent) { // ... // 为 Undo/Redo 动作添加处理程序 undoAction.setHandler(new UndoActionHandler(getViewSite(), undoContext)); redoAction.setHandler(new RedoActionHandler(getViewSite(), undoContext)); } ``` 4. 在 `createPartControl` 方法中为 `parent` 控件创建上下文菜单,并将 Undo/Redo 动作添加到上下文菜单中: ```java public void createPartControl(Composite parent) { // ... // 为 parent 控件创建上下文菜单,并将 Undo/Redo 动作添加到上下文菜单中 MenuManager menuMgr = new MenuManager(); menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); getSite().registerContextMenu(menuMgr, getSite().getSelectionProvider()); parent.setMenu(menuMgr.createContextMenu(parent)); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new Separator()); manager.add(undoAction); manager.add(redoAction); } }); } ``` 5. 在 `ViewPart` 类中添加以下方法: ```java public void executeCommand(final IUndoableOperation operation) { // 如果操作不可撤销,则返回 if (!operation.canUndo()) { return; } // 如果当前有未完成的撤消操作,则合并操作 if (undoOperation != null) { undoOperation.addContext(operation.getContext()); undoOperation.add(operation); } else { // 否则,开始新的撤消操作 undoOperation = operation; } // 注册撤消操作 IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory(); operationHistory.add(undoOperation); // 更新 Undo/Redo 动作的状态 undoAction.setEnabled(undoOperation.canUndo()); redoAction.setEnabled(undoOperation.canRedo()); // 将操作添加到 Undo/Redo 上下文中 undoContext.addMatch(undoOperation); } public void undo() { // 撤消上一个操作 IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory(); operationHistory.undo(undoContext, null, null); } public void redo() { // 重做上一个操作 IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory(); operationHistory.redo(undoContext, null, null); } ``` 6. 在 `ViewPart` 类中添加以下代码,以便在视图关闭时清除 Undo/Redo 上下文中的操作: ```java public void dispose() { // 清除 Undo/Redo 上下文中的操作 IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory(); operationHistory.dispose(undoContext, true, true, true); super.dispose(); } ``` 现在,您可以在 `executeCommand` 方法中执行所有需要撤消/恢复支持的操作,并且在菜单栏 Edit 中的 Undo/Redo 菜单项中使用 Undo/Redo 动作来撤消/恢复操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值