1. 程式人生 > >撤銷與反撤銷 功能實現

撤銷與反撤銷 功能實現

    你一定經常看見類似下面的圖示:
   
    它們就表示“撤銷”與“反撤銷”。在程式中,這種功能通常是使用Command模式實現的,本文也不例外。首先抽象定義Command,使用ICommand介面:
    publicinterface ICommand
    {
        
void Excute() ;
    }
    Excute表示執行該ICommand引用的目標的所包含的動作(或動作序列)。
    
    可撤銷的命令也是一種命令,所以從ICommand繼承:
   
    publicinterface IBackableCommand :ICommand
    {
        
void Undo() ;
    }
    一個可撤銷的命令表明呼叫其Excute方法後,再呼叫其Undo方法可以使被操作的物件回覆到之前的狀態。

    為了實現撤銷功能,我們需要一個堆疊來記錄所有已執行的可撤銷命令,為了實現反撤銷的功能,同樣,我們也需要一個堆疊來記錄所有已撤銷的命令。這個職責是由ICommandManager介面提供:
   
    publicinterface ICommandManager
    {
        
void ExcuteCommand(ICommand command) ;
        
void Undo() ;
        
void ReverseUndo() ;
//反撤銷

        
//以下事件可用於控制撤銷與反撤銷圖示的啟用event CbSimpleBool UndoStateChanged ; //bool引數表明當前是否有可撤銷的操作event CbSimpleBool ReverseUndoStateChanged ; //bool引數表明當前是否有可反撤銷的操作    }
    現在,我們來詳細分析一下,撤銷命令堆疊和反撤銷命令堆疊在何時Push命令物件、又在何時Pop命令物件:
(1)當執行完任何一個command後,reverseUndo堆疊清空
(2)當執行完一個不可撤銷的command後,undo堆疊清空
(3)當執行完一個可撤銷的command後,將其壓入undo堆疊
(4)當撤銷一個command後,將其轉移到reverseUndo堆疊

    基於此,我們就可以實現ICommandManager:
    public
class CommandManager :ICommandManager
    {
        
private Stack undoStack    =new Stack() ;
        
private Stack reverseStack =new Stack() ;

        
publicevent CbSimpleBool UndoStateChanged ; 
        
publicevent CbSimpleBool ReverseUndoStateChanged ; 

        
public CommandManager()
        {
            
this.UndoStateChanged         +=new CbSimpleBool(CommandManager_UndoStateChanged);
            
this.ReverseUndoStateChanged +=new CbSimpleBool(CommandManager_UndoStateChanged) ;
        }

        
privatevoid CommandManager_UndoStateChanged(bool val)
        {

        }

        
#region ICommandManager 成員publicvoid ExcuteCommand(ICommand command)
        {
            command.Excute() ;
            
this.reverseStack.Clear() ;

            
if(command is IBackableCommand)
            {
                
this.undoStack.Push(command) ;
            }
            
else
            {
                
this.undoStack.Clear() ;
            }

            
this.UndoStateChanged(this.undoStack.Count >0) ;
        }

        
publicvoid Undo()
        {
            IBackableCommand command 
= (IBackableCommand)this.undoStack.Pop() ;
            
if(command ==null)
            {
                
return ;
            }

            command.Undo() ;
            
this.reverseStack.Push(command) ;

            
this.ReverseUndoStateChanged(this.reverseStack.Count >0) ;
        }

        
publicvoid ReverseUndo()
        {
            IBackableCommand command 
= (IBackableCommand)this.reverseStack.Pop() ;
            
if(command ==null)
            {
                
return ;
            }

            command.Excute() ;
            
this.undoStack.Push(command) ;

            
this.UndoStateChanged(this.undoStack.Count >0) ;
            
this.ReverseUndoStateChanged(this.reverseStack.Count >0) ;
        }
        
#endregion
    }

    本文介紹的撤銷與反撤銷功能是與應用無關的,所以可以在不同的應用中複用,你只需要根據你自己的應用需求來實現對應的ICommand介面和IBackableCommand介面就可以立即使用撤銷與反撤銷功能了。




相關推薦

撤銷撤銷 功能實現

    你一定經常看見類似下面的圖示:        它們就表示“撤銷”與“反撤銷”。在程式中,這種功能通常是使用Command模式實現的,本文也不例外。首先抽象定義Command,使用ICommand介面:    publicinterface ICommand  

HTML5 中 canvas 繪圖的撤銷撤銷功能實現

> 實現原理: 儲存快照:每完成一次繪製操作則儲存一份 canvas 快照到 canvasHistory 陣列(生成快照使用 canvas 的 toDataURL() 方法,生成的是 base64 的圖片); 撤銷和反撤銷:把 canvasHistor

Command(命令)——物件行為型模式(通過Command設計模式實現WinForm表單維護的撤銷重做功能

Command(命令)——物件行為型模式(通過Command設計模式實現WinForm表單維護的撤銷與重做功能) 意圖 動機 典型場景 程式碼實現 ICommand介面,定義execute和undo操作 OperationCom

剪貼簿——C# 複製、貼上、撤銷、剪下功能實現

使用RichTextBox控制元件實現系統剪下板功能: 複製: private void CopytoolStripMenuItem_Click(object sender, EventArgs e) {//複製 try { this.Cursor =

單例模式的序列化序列化實現需要實現readResolve()方法

package com.linruby.singleton; import java.io.Serializable; public class SingletonObject implements Serializable { private static final Singleto

PHP視訊外掛功能實現

php與視訊播放器外掛的功能,說白了就是前端是播放器的外掛,直接呼叫後端傳遞過來的播放地址,還有其他的一些資訊,比如封面圖面,名稱,播放時間,地址等等。這些需要在後臺把這些封裝起來,可以儲存在資料庫裡,方便呼叫。以上就是思路。想起來是不是很簡單。做起來也差不多咯。 首先,前端

檔案上傳下載的功能實現

檔案上傳 檔案上傳原理分析 1、檔案上傳的必要前提: 一、進行檔案上傳時只能使用post方式提交表單 二、表單必須新增一個屬性:enctype=”multipart/form-data” 三、用於上傳檔案的元素必須時 2、enctype屬性 作

Vim使用技巧:撤銷恢復撤銷

color encoding back -s 小寫 使用 如何 1.0 XML 在使用VIM的時候,難免會有輸錯的情況,這個時候我們應該如何撤銷,然後回到輸錯之前的狀態呢? 解決方法:使用u(小寫,且在命令模式下)命令。 但如果有時我們一不小心在命令模式

Android 百度地圖開發--- 導航功能輸入起始地址實現導航,地址解析解析的使用

本人主要介紹安卓開發使用百度地圖實現導航功能,使用者可以輸入當前位置和目的地,實現導航。 首先,我們需要當用戶輸入具體接到地址後將具體街道的地址轉化為經度和緯度,然後實現定位,因此,首先來講解一下地址解析,百度地圖API提供Geocode類進行地址解析,我們可以通過Geo

jquery實現全選/功能

click demo lar sim llc res rip rop 個數 <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content="text/h

PHP實現簡單的評論回復功能還有刪除信息

技術分享 mit [0 ech ges get values width 錯誤 我們首先先看一下功能 上面黑色的是評論的下面紅色的字體是回復的 再來看看怎麽實現的 1.發布評論 <form action="pinglunchili.php" method="po

Java核心類庫-IO-對象流(實現序列化序列化)

.get throws 反序 code row cts new java cep 使用對象流來完成序列化和反序列化操作:   ObjectOutputStream:通過writeObject()方法做序列化操作的   ObjectInputStream:通過readObje

jQuery實現全選功能

ava -type func tex solid blog pan 原因 input 廢話不說,直接上代碼! <html> <head> <meta http-equiv="Content-Type" content="text/html;

Vue.js 開發實踐:實現精巧的無限加載分頁功能

cti head 設定 命令 webpack transform style time default https://segmentfault.com/a/1190000005351971#articleHeader9 本篇文章是一篇Vue.js的教程,目標在於用一

PHP連接數據庫實現多條件查詢分頁功能——關於租房頁面的完整實例操作

ots cnblogs 信息 val 租房 btn earch 拼接 round 租房頁面如圖: 代碼如下: <!DOCTYPE html><html> <head> <meta charset="UTF-8"

問題查找功能實現的註意事項

適合 包含 來看 for循環 代碼 類型 也會 inpu 格式   寫這篇文章之前,猶豫了很久要不要寫一寫關於數組和集合的應用問題,對難點進行分析。但隨後想到目前對數組和集合只是簡單應用,而遇到的問題也只是基礎知識不牢固,對其余的知識帶入不強導致的,仔細分析、

Delphi實現DBGrid全選和功能

web log con ont procedure del div 操作 var Delphi實現Dbgrid全選和反選、清除全選的功能,不管是在Delphi下,還是在WEB開發中,這種功能都是很實用的,是進行數據批量操作的基礎。本模塊就是實現了為Delphi的DB

git merge 撤銷git 回滾

eve comm 需要 恢復 clas .com class sts nsh git merge提交後恢復 http://blog.psjay.com/posts/git-revert-merge-commit/ git回滾 https://www.jianshu.com/

Apache Avro 序列化序列化 (Java 實現)

Avro像兩個交流一樣要找一個互相能理解的語言, 在國內為普通話, 跑國外多用英語相通, 兩個進程間通信也需要找一個大家都能理解的數據格式. 簡單的如 JSON, XML, 那是自我描述性格式, XML 有 Schema 定義, 但尚無正式的 JSON Schema 規範. 在講求效率的場合, 純文本式的數據

jquery 實現頁面全選功能

python<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head>&