Я написал два текстовых редактора с нуля, и они оба используют очень примитивную форму функциональности отмены / возврата. Под «примитивным» я подразумеваю, что функциональность была очень проста в реализации, но она неэкономична в очень больших файлах (скажем, >> 10 МБ). Тем не менее, система очень гибкая; например, он поддерживает неограниченные уровни отмены.
По сути, я определяю структуру как
type
TUndoDataItem = record
text: /array of/ string;
selBegin: integer;
selEnd: integer;
scrollPos: TPoint;
end;
, а затем определить массив
var
UndoData: array of TUndoDataItem;
Тогда каждый член этого массива указывает сохраненное состояние текста. Теперь при каждом редактировании текста (нажатие клавиши вниз, возврат на клавишу вниз, удаление клавиши вниз, вырезание / вставка, выделение, перемещаемое мышью и т. Д.), Я (пере) запускаю таймер, скажем, одну секунду. При срабатывании таймер сохраняет текущее состояние как новый элемент массива UndoData
.
При отмене (Ctrl + Z) я возвращаю редактор в состояние UndoData[UndoLevel - 1]
и уменьшаю UndoLevel
на единицу. По умолчанию UndoLevel
равен индексу последнего члена массива UndoData
. При возврате (Ctrl + Y или Shift + Ctrl + Z) я возвращаю редактор в состояние UndoData[UndoLevel + 1]
и увеличиваю UndoLevel
на единицу. Конечно, если таймер редактирования запускается, когда UndoLevel
не равен длине (минус один) массива UndoData
, я очищаю все элементы этого массива после UndoLevel
, как это обычно бывает в Microsoft Windows (но Emacs лучше, если я правильно помню - недостаток подхода Microsoft Windows заключается в том, что, если вы отмените много изменений, а затем случайно отредактируете буфер, предыдущий контент (который был отменен) будет навсегда потерян). Возможно, вы захотите пропустить это сокращение массива.
В программе другого типа, например, в редакторе изображений, может применяться та же техника, но, конечно, с совершенно другой структурой UndoDataItem
. Более продвинутый подход, который не требует большого количества памяти, состоит в том, чтобы сохранять только изменения между уровнями отмены (то есть вместо сохранения "alpha \ nbeta \ gamma" и "alpha \ nbeta \ ngamma" \ ndelta ", вы можете сохранить" alpha \ nbeta \ ngamma "и" ADD \ ndelta ", если вы понимаете, о чем я). В очень больших файлах, где каждое изменение мало по сравнению с размером файла, это значительно уменьшит использование памяти для отмененных данных, но это сложнее в реализации и, возможно, более подвержено ошибкам.