2010-10-05 41 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)。

这样,当用户执行撤消操作时,他们不会看到每一次击键。相反,撤消发生在逻辑组中。