2010-08-27 2 views
13

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

+0

Какой язык вы используете? – t0mm13b

+0

Язык есть java – SjB

+2

. Вы должны посмотреть http://stackoverflow.com/questions/49755/design-pattern-for-undo-engine – FabienAndre

ответ

14

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

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

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

+7

И наоборот, вы можете сделать одну команду, которая знает, как и отменить, и повторить сам; когда вы отмените действие, вытащите его из стека отмены, вызовите действие отмены и просто переместите его в стек повтора. Когда вы вызываете redo, поместите верхнюю часть стека повтора, вызовите операцию повтора и нажмите на стек отмены. Это избавляет вас от необходимости создавать новые объекты все время; вы просто перетасовываете существующие. – derekerdmann

+0

@derekerdmann: спасибо за наконечник. –

4

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

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

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

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

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

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

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

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

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

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

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

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

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

Нико

8

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

  • «Командование» Паттерн

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

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

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

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

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

+2

Техника «OO над неизменными объектами» звучит интересно. Можете ли вы предоставить какие-либо ссылки, которые я мог бы проверить? Я предполагаю, что вы используете OO для обозначения «Ориентация объекта»? Благодарю. – ericwa

+1

О, я думаю, что нашел что-то на отмене с неизменяемыми объектами: http://stackoverflow.com/questions/1812978/undo-redo-with-immutable-objects – ericwa

2

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

SWT Undo Redo

6

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

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

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

+1

Более простой способ сделать это - сравнить длины содержимого до и после его изменения и только сохранить редактирование, если оно было изменено более чем на 20 символов с момента последнего сохранения редактирования. –