0

我正在尝试在 Visual-C++ 中制作一个相当大的应用程序,现在我正在尝试添加撤消/重做功能。

有相当多的事件(按钮单击、标签文本更改等),我想找到一种方法来撤消/重做,而无需向每个函数添加代码。例如,我想要一个可以读取完成的每个事件并自动存储它的类。然后在我的撤消/重做事件中,我可以获取存储的最新操作。

如果那不可能,我不会介意其他方式。

有什么帮助吗?

4

3 回答 3

2

声明一个代表两个操作的类 - 撤消和重做。同时创建该类的两个向量。

对于要应用撤消/重做的每个操作,将该类的实例推送到撤消向量中。应该有与要撤消的操作一样多的派生类。

例如,如果单击按钮将背景绘制为绿色,则创建一个类实例,其 undo 方法将背景绘制为先前的颜色,其 redo 方法将背景绘制为绿色,并将其填充到撤消向量中。当您撤消时-您弹出最后一个类实例并调用其撤消方法,该方法会将背景绘制为以前的颜色。然后你把它推到重做向量。

当您重做时,您将类实例的重做向量弹出顶部并调用其重做方法,然后将其填充回撤消向量。

有一些极端情况(边界),遇到时你会解决它们.. :-)

于 2012-04-28T21:20:24.687 回答
1

我试图在一个小型实验库中实现类似的目标:https ://github.com/d-led/undoredo-cpp 。它包含一个TransactionStore类似于CodeChords 人建议的实现。您可能需要真正为每个可撤消对象添加功能,并注意对象生命周期,以防您的操作涉及对象构造或销毁

于 2012-08-27T07:53:25.480 回答
1

您的所有事件是否都通过某种队列?默认情况下,在 c++ 中没有这样的队列(有一个 Windows 操作系统级别的事件队列,但它可能已经在 c++-cli 中管理并且无法使用,并且您没有指出这是否与您的问题密切相关),可能有一些我不知道的其他构造。

如果您有一些中央队列,那么只需在事件通过时捕获事件并知道如何撤消每个操作。如果没有中央队列,那么我认为没有比更改每个可撤消函数以创建某种撤消对象并将其存储在某种撤消队列中更容易的方法了。

在没有大型中央工作队列的纯 .net 或 C++ 环境中,我将创建一个是和撤消条目的类,它实现一个方法/成员函数来撤消和另一个重做/完成工作。但是对于撤消功能,这可能只是一个 .net 委托或 ac 样式的函数指针,以及一个参数列表。如果您创建一个动作撤消/重做类,它可以是一个模板或泛型,用于存储指向 do 和 undo 函数的指针/委托,以及最初调用时的参数列表。

这些可以运行以撤消已完成的操作。它们将被插入到某种队列容器中,容器的种类似乎并不重要,只要它保留顺序,您应该为您的应用程序选择最好的 std、.net 或其他容器。当您不再需要它们时,您可以丢弃旧的。执行时,必须删除最后插入队列的条目以保持一致性。

如果您还需要重做功能,那么您完成的操作队列必须是可迭代的,并且使用具有可撤销/重做所需操作的方法/成员函数的类是最简单的。您将拥有某种迭代器、指针、索引或标记,指示您撤消了多远。每次请求撤消时,您必须向后移动标记(按时间顺序更早)并在队列中的该点执行撤消命令。如果请求重做,则指示的当前项执行其重做指令,然后迭代器向前(按时间顺序)通过队列,或者如果您位于队列中最前面的项,则忽略(我假设)。

如果您想深入研究,但您没有办法表明您想要这样做,您可以将您的应用程序集中在操作队列周围。您可能不需要更改实现此方法的函数。您的用户界面(我假设,可以很容易地成为您的 API)功能,将操作(支持执行和撤消)插入队列,然后命令队列执行。如果它们的副作用是已知的并且是可逆的,则您不必更改现有功能。但是,您需要更改所有调用者以执行操作而不是直接调用,并且您需要编写执行撤消操作的对应项。

于 2012-04-28T21:43:04.450 回答