現代軟體很多都配備了undo/redo功能,這個功能對於使用者來說是十分方便,可以明顯節約使用者時間,增加軟體的易用性,其中以office和 autocad最為典型。本文以.net環境中最常用的c#語言為例,詳細分析了實現undo/redo功能的必要技術,並提供了可執行的c#**清 單。
實現undo/redo功能,就必須記錄使用者的操作和這些操作發生前受該操作影響的物件的值。當然不是每個操作都是值得關注的,比如「開啟檔案」,「最大化視窗」等這類不改變軟體核心物件資料的操作,是完全不必記錄下來的。
其中一些操作只改變乙個物件的乙個域的值,而一些操作可以改變很對個物件的多個域的值(例如autocad中的分解命令,可以同時改變n個物件的狀態)。為
了簡化問題,我們肯定希望不管是只改變乙個物件的某個域的操作(被稱為原子操作)還是一次改變多個物件的操作(被稱為復合操作)都被以一種單一介面被提
供 。這就要對操作進行包裝,將原子操作打包成復合操作,或者說把復合操作偽裝成原子操作,因為對於操作的呼叫者來說,這完全是透明的,他將感覺不到自己
呼叫的是原子操作還是復合操作,也不必關心這個問題。
乙個復合操作到底含有多少原子操作是事先無法確定的。arraylist
是.net提供的一種可變的萬能陣列,它實際上是乙個****物件,但是它的使用方式上看上去更像個可變的一維陣列,很適合用於這種未知長度的情況。所以
復合操作用arraylist存放是合適的。
接下來的事情就是理解undo/redo的本質了。使用者在undo時,軟體到底做了些什
麼呢?上面分析了所有有效操作都必須被記錄下來,而且是被存放在陣列或者是鍊錶中,當使用者undo時,顯然是要從陣列或者鍊錶中取回被儲存的資料,然後賦
值給相對應的物件。redo發生時大概也是發生了這些事情,只是方向和undo剛好是相反的。使用者的操作不一定總是要插入陣列/鍊錶的末端。舉個例子:當
使用者的先進行了10個操作,然後又undo掉了5個操作,然後又進行了乙個操作,這個操作是應該儲存在陣列/鍊錶的第11個位置上還是應該儲存在第6個位
置上呢?答案顯然是後者。只要又進行了乙個操作,先前的被儲存在undo陣列/鍊錶中的第6到10個記錄將全部變成無效。
那麼使用者在redo時發生了什麼呢?還是剛才的例子,使用者undo掉5個操作後又redo了3次,顯然應該和使用者只進行了前8個操作是等價的。如果使用者undo掉5個操作而沒有redo,而是又進行了3個其他操作呢?這時候他再redo會怎樣?根據經驗,結論是無法redo了,redo操作必須緊隨undo才行。因為undo陣列中第9,10兩個操作早已經是無效了,再redo它們,是絕對錯誤的事情。
至此,關於undo/redo的分析就完成了,接下來就是編碼。下面提供的是在vs2005上編譯通過的c#源**:
publicclass
cundo
} private
bool bcanredo = false;//
當前狀態下是否可以進行redo操作
public
bool
canredo
} public
bool bstartstate = false;//
指示是否是第一次記錄操作
private
int iactionlistlength= 0;//
有效操作佇列的長度,它並不一定等於actionlist.count
private
int icurrentactionpointer= -1;//
指向actionlist當前操作的指標,新新增的操作從該
//public cundo(int
maxundotime)
public
int actionlistlength//
獲取當前操作佇列的實際長度
} public
int currentactionpointer//
獲取當前undo指標的位置
} //向操作佇列中加入操作,插入成功就返回true,否則為false
public
bool
addactionintoactionlist(cactionnode act)
else
return
false
; }
public
bool undo(int
iundotime)
bcanredo = true;//
如果成功undo,就置bcanredo為真
return
true
; }
public
bool redo(int
iredotime)
bcanundo = true;//
如果成功redo,就置bcanundo為真
文字錄入無限制Undo,Redo的實現
這裡只針對edit的內容做乙個簡單的undo,redo功能 原理就是,將新增字元和相關資訊新增到undo列表,在undo動作時,取記錄資訊,並在edit中刪除新增的字元,然後將此動作新增到redo列表,以便恢復。本程式只對文字框文字的順序增加做了處理,對於任意位置的刪除,複製貼上等沒有進行處理,大家...
C 類的實現方式
假設有乙個簡單類如下 class test int getm static void print 呼叫如下 test t 1 a.getm test print c 類實現方式 struct test 建構函式 void test initialize test this,int i 普通成員函式中...
C 繼承的實現方式
虛方法 如果要在派生類中繼承方法或屬性,那麼就必須在基類中將該屬性宣告為virtual。方法或屬性在預設情況下是不虛擬的,所以如果不在基類中顯示宣告,在派生類中用override重寫該方法時就會報錯。當然,如果在派生類中用new來隱藏基類方法也沒有問題。我們看下面乙個例子 public class ...