Как спроектировать отмену и повтор в текстовом редакторе?

Часть моего проекта заключается в написании текстового редактора, который используется для ввода некоторых правил, компиляции моего приложения и его запуска. Написание компилятора было завершено, а выпуск бета-версии. В финальной версии мы должны добавить отменить и повторить в текстовом редакторе. Я использую файл и периодически сохраняю его для текстового редактора. Как оформить отмену и возврат в мой текстовый редактор? Что изменилось в структуре персистента файла?

14
задан phuclv 12 August 2019 в 06:36
поделиться

7 ответов

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

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

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

14
ответ дан 1 December 2019 в 06:38
поделиться

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

3
ответ дан 1 December 2019 в 06:38
поделиться

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

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

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

  • фрагменты действия: они являются частью более крупного действия и не могут быть отменены или повторены отдельно (например, перемещение мыши)
  • действия: один или несколько фрагментов действия, образующих значимое изменение, которое можно отменить или повторить, но которые не отражаются в редактируемом документе как измененные на диске (например, выбор элементов)
  • изменения документа: одно или несколько действий, которые изменяют отредактированный документ так, как он будет сохранен на диск. (например, изменение, добавление или удаление элементов)
  • сохранение документа: текущее состояние документа явно сохраняется на диск - в этот момент мой редактор отбрасывает историю отмен, так что вы не можете отменить после сохранения
4
ответ дан 1 December 2019 в 06:38
поделиться

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

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

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

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

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

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

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

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

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

Нико

4
ответ дан 1 December 2019 в 06:38
поделиться

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

  • шаблон проектирования «Команда»

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

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

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

«ОО над неизменяемыми объектами» — чистая драгоценность. Вероятно, это не станет мейнстримом еще через 10 лет; )

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

8
ответ дан 1 December 2019 в 06:38
поделиться
2
ответ дан 1 December 2019 в 06:38
поделиться

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

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

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

6
ответ дан 1 December 2019 в 06:38
поделиться
Другие вопросы по тегам:

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