2010-10-05 66 views
2

我寫了一個文本編輯器程序在C++中有簡單的命令:LEFT,RIGHT,HOME,END,BACKSPACE,DELETE,INSERT,現在我需要執行UNDO和REDO功能。在我的程序中,用戶必須能夠撤消最多十個命令。我想使用矢量實現來實現這一點,但我不知道如何設置它。我不知道如何將光標位置和字符存儲到向量中。有人可以提供一些幫助嗎?需要幫助編寫撤消/重做功能的文本編輯器程序

#ifndef CURSOR_H 

#define CURSOR_H 



#include <stdlib.h> 
#include <iostream> 

template <class Object> 
class Cursor; 
// Incomplete Declaration 

template <class Object> 
class CNode 
{ 
     public: 

       CNode(const Object & theElement = Object(), CNode * n = NULL) : element(theElement), next(n) { } 
       Object element; 
       CNode *next; 
       friend class Cursor<Object>; 
}; 

template <class Object> 
class Cursor 
{ 
public: 
    Cursor(); 
    bool isEmpty() const; 
    void makeEmpty(); 
    void left (); 
    void right (); 
    void del (); //This is the delete operation. I named it del instead of delete as delete conflicts with a C++ keyword. 
    void back (); 
    void insert(const Object & x); 
    void home (); 
    void end (); 
    void undo (); 


private: 

    void printText () ; 

    CNode<Object> *header; 
    CNode<Object> *cursorPosition; 

}; 
//#include "Cursor.cpp" 
#endif 

回答

3

你想用一個deque,使您可以添加和從前面或後面取出;當添加一條命令時,將它添加到後面,當撤消時將它從後面移除,並且當你達到11條命令時從前面刪除一條命令。

+0

一個環形緩衝區將允許相同的動作,而不需要任何分配/解除分配。 – 2010-10-05 02:40:36

+0

@本,非常真實。但是環形緩衝區不是標準的一部分,我發現了一個渴望與標準容器保持一致的願望;也許我錯了。 Boost提供了一個:http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html – 2010-10-05 02:45:43

+0

「檢測出堅持使用標準容器的願望」:CNode <>是對相反,雖然提到了vector <>。 – 2010-10-05 02:55:51

2

看那Memento Design Pattern並在GOF

它存在於這個非常具體的要求。您可能必須與其它設計模式(如命令,迭代器,輕量級等)使用它

備忘錄意向

在不違反封裝, 捕捉和外部化對象的 內部狀態,以便對象可以在稍後恢復到此狀態。

命令意圖

封裝的請求 爲對象,從而讓你 參數不同 請求的客戶端,隊列或日誌請求,並 支持可撤銷的操作。

1

一些其他的事情要考慮:

一般情況下,你不想申請撤銷/重做光標移動(即他們將在十個命令界限的界限沒有影響)。當撤消/重做刪除或插入文本時,當然必須在執行操作之前將光標放在適當的位置。如果用戶在不執行任何光標移動或更正(退格鍵)的情況下鍵入多個字符,則通常在應用撤銷/重做時將這些字符視爲單個單位。

+0

+1:讓我覺得花費這麼多時間/空間來解釋很多相同的問題會感覺很愚蠢...... – 2010-10-05 02:54:10

+0

他們需要在這個網站上的人工智能識別別人是否輸入相同的答案,因爲你是和建議聯合作者:) – tcrosley 2010-10-05 03:13:18

0

對於要能夠撤消每個操作(即大概插入,退格鍵和刪除,而不是光標移動),我們可以列出了「取消」的過程:

  • 插入 - >位置光標移動到該字符併發出德爾
  • 德爾 - 在後面的字符>將光標定位併發出插入
  • 退格 - >光標在後面的字符位置併發出插入

不幸的是,您的遊標使用指針,並且當您撤銷刪除/退格時,新分配的代碼可能與之前不在同一地址,這可能導致嘗試使用該指針地址的更早的撤銷步驟失效。選項包括:

  • 一些額外的數據結構來跟蹤指針以這種方式已經失效,並用新值重新填充他們,如果相應的元素被重新創建(痛苦)

  • 找到一個更確定的方式找到在CNode列表

    • 絕對索引到文檔中的正確索引(但可能是難以計算和緩慢移動到)
    • 保存您的光標在您的撤消歷史記錄中移動
      • 將任意數量的散佈光標移動進行10次實質性編輯(刪除,退格,插入)需要動態大小的容器,並且您會攜帶相當多的「冗長行李」
      • ,你可以在每個實質性編輯的一個固定大小的列表掛光標移動的動態列表關每一個元素(不到哪去,雖然)

(由於是,您Cnode列表不會出現雙鏈接,所以我不這樣做?看你怎麼可以向左移動沒有一個非常痛苦重申通過從頭部元素中的「文件」 ...)

整理出這個索引/光標移動問題之後,你必須決定之間:

  • 每次操作之後,使用一個雙端隊列保存撤消信息:

    結構歷史 { 一個指示器,其操作來撤消(例如枚舉歐普{左,右,插入,刪除...}) 僅插入操作:一個對象值 }

    然後有一些上撤消處理功能讀取這些記錄歷史,並協調它們所描述的操作,或

    當執行一個操作
  • ,推函數對象到您的deque編碼的撤消和重做操作(在調用光標對象的方法而言),所以實際上做撤消或只是重做操作涉及執行該對象(即,撤銷/重做操作是在編輯時分組的「黑匣子」)/這更優雅和靈活,但可能不太熟悉開始/ i中間程序員因此可能更難以正確。 boost庫有很好的輔助功能。

1

恭喜包括撤銷/重做。這在任何編輯器中都是一個很棒的功能。它仍然會變得棘手。這裏有一些想法給你(所有的手搖,沒有代碼)。我建議瞭解一下Command Design Pattern。你想要做的是設計一個'命令'類,它的一個實例可以「執行」一個命令(如插入字母'A'),以及「撤消」本身。

當用戶調用某個命令時(比如添加字母'A'),您可以在命令中定義其「Do」以插入「A」,同時定義其「撤消」以刪除A,然後添加將它放到撤消列表的頂部,然後「執行」它。

不要限制你的undos只有10個。爲什麼不使它無限?

無論您使用哪種結構來創建可撤銷命令列表,通常的行爲是,如果您已撤銷到某個級別,然後開始在該點進行編輯,那麼當前級別上的所有重做應該是丟棄。

0

我同意其他人關於在執行「do」命令時捕獲可撤銷命令。

我也建議週期性的工作,並結合撤銷命令。

例如,如果您的撤消命令是:

刪除A,刪除B,刪除C,左箭頭,左箭頭,右光標,左箭頭。

轉換它僅僅是,

刪除 「ABC」,左箭頭(2)。

這樣,當用戶執行撤消操作時,他們不會看到每一次擊鍵。相反,撤消發生在邏輯組中。