Как реализована функция UNDO и REDO в любом редакторе TEXT? [Дубликат]

Вы используете объект, содержащий ссылку нулевого значения. Таким образом, он дает пустое исключение. В примере строковое значение равно null, и при проверке его длины произошло исключение.

Пример:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

Ошибка исключения:

Необработанное исключение:

System.NullReferenceException: ссылка на объект не установлена ​​в экземпляр объекта. в Program.Main ()

14
задан Sajad Bahmani 27 August 2010 в 13:32
поделиться

8 ответов

Вы можете моделировать свои действия как команды , которые вы держите в двух стеках. Один для отмены, другой для повтора. Вы можете скомпоновать команды для создания более высокоуровневых команд, например, когда вы хотите отменить действия макроса; или если вы хотите группировать отдельные нажатия одного слова или фразы в одном действии.

Каждое действие в вашем редакторе (или повторное действие) генерирует новую команду отмены, которая поступает в стек отмены ( а также очищает стек повтора). Каждое действие отмены создает соответствующую команду redo, которая переходит в стек повтора.

Вы также можете, как упоминалось в комментариях derekerdmann , объединить команды отмены и повтора в один тип команды, которая знает, как отменить и повторить действие.

14
ответ дан Community 31 August 2018 в 19:35
поделиться

Вот фрагмент, который показывает, как SWT поддерживает операции Undo / Redo. Возьмите его как практический пример (или используйте его напрямую, если ваш редактор основан на SWT):

SWT Undo Redo

2
ответ дан Andreas_D 31 August 2018 в 19:35
поделиться

Это задание для шаблона команды .

3
ответ дан DanDan 31 August 2018 в 19:35
поделиться

Если вы не хотите ничего фантастического, вы можете просто добавить UndoManager . Ваш Document будет запускать UndoableEdit каждый раз, когда вы добавляете или удаляете текст. Чтобы отменить и повторить каждое изменение, просто вызовите эти методы в UndoManager.

Недостатком этого является UndoManager, который добавляет новое редактирование каждый раз, когда пользователь вводит что-то, поэтому набрав «яблоко», вы оставите 5 изменений , отменяется по одному. Для моего текстового редактора я написал обертку для редактирования, в которой хранится время, которое было сделано в дополнение к изменению и смещению текста, а также UndoableEditListener, который объединяет новые изменения в предыдущие, если есть только короткий промежуток времени между (0,5 секунды хорошо работает для меня).

Это хорошо работает для общего редактирования, но вызывает проблемы, когда делается массовая замена. Если у вас был документ с 5000 экземплярами «яблока», и вы хотели заменить его «оранжевым», вы в конечном итоге получили бы 5000 исправлений, сохраняя «яблоко», «оранжевое» и смещение. Чтобы уменьшить объем используемой памяти, я рассматривал это как отдельный случай для обычных изменений и вместо этого хранили «яблоко», «оранжевый» и массив из 5000 смещений. Я еще не успел применить это, но я знаю, что это вызовет некоторые головные боли, когда несколько строк соответствуют условию поиска (например, регистр без учета регистра, поиск по регулярному выражению).

6
ответ дан lins314159 31 August 2018 в 19:35
поделиться

Ничего себе, какова вероятность того, что я буквально за последний час внедрил undo / redo в текстовом редакторе WYSIWYG:

Основная идея - либо сохранить все содержимое текстового редактора в массиве , или разницу между последним правлением.

Обновите этот массив в значительных точках, то есть каждый несколько символов (проверьте длину содержимого каждого нажатия клавиши, если его более чем на 20 символов отличаются, то создайте точку сохранения ). Также при изменении стиля (если используется расширенный текст), добавление изображений (если это разрешено), вставка текста и т. Д. Вам также нужен указатель (просто переменная int), чтобы указать, какой элемент в массиве является текущим состоянием editor)

Сделать массив заданной длиной. Каждый раз, когда вы добавляете точку сохранения, добавьте ее в начало массива и переместите все остальные точки данных на один. (последний элемент в массиве будет забыт, как только у вас будет столько точек сохранения).

Когда пользователь нажимает кнопку отмены, проверьте, совпадают ли текущие содержимое редактора с последним сохранением (если это не так, то пользователь внес изменения со времени последнего сохранения, поэтому сохраните текущее содержимое редактора (чтобы его можно было переделать), сделайте редактор равным последней точке сохранения и сделайте указатель variable = 1 (2-й элемент в массиве) .Если они такие же, то никаких изменений со времени последнего сохранения не было, поэтому вам нужно отменить до этой точки. Чтобы сделать это, увеличьте значение указателя + 1, и сделайте содержимое редактора = значение указателя.

Чтобы повторить, просто уменьшите значение указателя на 1 и загрузите содержимое массива (убедитесь, что вы достигли конца массива ).

Если пользователь вносит изменения после отмены, то перемещайте ячейку массива с указанным значением до ячейки 0 и переместите остальную часть на ту же сумму (вы не хотите, чтобы t o повторить другие действия, если они внесли разные изменения).

Еще одна важная точка улова - убедитесь, что вы добавили только точку сохранения, если содержимое текстового редактора действительно изменилось (в противном случае вы получите дубликат сохранить точки, и похоже, что отмена ничего не делает для пользователя.

Я не могу помочь вам с java-спецификой, но я рад ответить на любые другие ваши вопросы,

Нико

4
ответ дан Nico Burns 31 August 2018 в 19:35
поделиться

В основном есть два хороших способа:

  • шаблон дизайна «Command»
  • с использованием только OO над неизменяемыми объектами , где все - это просто неизменные объекты из неизменяемых объектов, сделанные из неизменяемых объектов (это менее распространено, но чудесно изящно, когда сделано правильно)

Преимущество использования OO над неизменяемыми объектами над наивными команда или наивное undo / redo - вам не нужно много об этом думать: не нужно «отменять» действие и не нужно «переигрывать» все команды. Все, что вам нужно, это указатель на огромный список неизменяемых объектов.

Поскольку объекты неизменны, все «состояния» могут быть невероятно легкими, потому что вы можете кэшировать / повторно использовать большинство объектов в любом состоянии.

«OO над неизменными объектами» - это чистая жемчужина. Вероятно, он не станет мейнстримом еще до 10 лет. )

P.S: выполнение OO над неизменяемыми объектами также удивительно упрощает параллельное программирование.

8
ответ дан NoozNooz42 31 August 2018 в 19:35
поделиться

Вы можете сделать это двумя способами:

  • сохранить список состояний редактора и указатель в списке; undo перемещает указатель назад и восстанавливает состояние там, redo движется вперед вместо этого, делая что-то, отбрасывает все, кроме указателя, и вставляет состояние как новый верхний элемент;
  • не сохраняет состояния, а действия, которые требует, чтобы для каждого действия у вас было противодействие, чтобы отменить действие этого действия.

В моем (диаграммном) редакторе есть четыре уровня изменений состояния:

  • : это часть более крупного действия, а не отдельно отменяемая или повторная (например, перемещение мыши)
  • действия: один или несколько фрагментов действия, которые образуют значимые изменения, которые могут быть отменены или переделаны, но которые не отражаются в отредактированном документе, как измененный на диске (например, выбор элементов)
  • изменения документа: одно или несколько действий, которые изменяют отредактированный документ, поскольку он будет сохранен на диске (например, изменение, добавление или удаление элементов)
  • документ сохраняет: текущее состояние документа явно сохраняется на диске - на данный момент мой редактор отбрасывает историю отмены, поэтому вы не можете отменить сохранение
4
ответ дан reinierpost 31 August 2018 в 19:35
поделиться
2
ответ дан Vladislav Rastrusny 31 August 2018 в 19:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: