Есть какие то типовые варианты создания функции отмена?

Модератор: Модераторы

Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Есть какие то типовые варианты создания функции отмена?

Сообщение Sharfik »

Функция Отмена последних действий иногда очень полезная, но понятия не имею какими методами ее можно организовать в программах.
Если вся программа построена на классах наследованных от TObject например, то в каждом случае надо самому все реализовывать или есть какие то средства для "сливания" предыдущих значений памяти в хранилище отдельное?
MiniQ
новенький
Сообщения: 81
Зарегистрирован: 28.01.2013 16:31:55

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение MiniQ »

Реализовывать нужно самому.
Например хранить отдельно "старые" объекты и новые.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Sharfik »

MiniQ писал(а):Например хранить отдельно "старые" объекты и новые.

Я что то зациклился на мысли о хранении значения переменных, полностью отдельно объект и правда проще слить. Спасибо.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение zub »

Я стараюсь хранить минимально возможный набор данных для отката - сохранять целый объект накладно, особенно при возможности массированых изменений. Вообще тема сложная и индивидуальная - единого решения нет.
Совет - undo\redo нужно вводить какможно раньше (ну или хотябы продумать как оно будет), внедрять это хозяйство в уже рабочий код - та еще каторга
stanilar
постоялец
Сообщения: 289
Зарегистрирован: 09.03.2010 18:09:02

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение stanilar »

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

Сам подумываю над таким компонентом.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Mirage »

Есть паттерн, сильно облегчающий реализацию undo/redo, а также дающий доп. плюшки:
Каждый тип операции модификации данных (коих по идее немног - изменение свойств чего-то, модификация данных и т.п.) оборачивается в класс с одним методом - Perform() допустим.
Первый его вызов совершает модификацию данных, второй - отменяет. Третий опять совершает и т.д.
Как это делается - сериализацией или как-то по-другому уже другой вопрос. Зависит.
И да, желательно сразу так делать, хотя, если программа написана вменяемо, то выделить классы операций должно быть несложно и уже существующем коде.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение zub »

>>оборачивается в класс с одним методом - Perform() допустим.
не все операции одинаково выглядят в ундо\редо, такчто метода лучше 2
MiniQ
новенький
Сообщения: 81
Зарегистрирован: 28.01.2013 16:31:55

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение MiniQ »

Mirage писал(а):Первый его вызов совершает модификацию данных, второй - отменяет. Третий опять совершает и т.д.

Что-то мудрено. А если мне нужно взглянуть, как было 10 операций назад? Т.е. откатить назад 10 операций и потом вернуть все в текущее состояние.
Вот этот патерн "первый вызов, второй вызов" как будет работать?
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Лекс Айрин »

MiniQ писал(а):Что-то мудрено. А если мне нужно взглянуть, как было 10 операций назад?


Думаю, проще сделать ссылку на следующее/предыдущее изменение. (то есть, использовать список операций)
ViTality
постоялец
Сообщения: 308
Зарегистрирован: 05.10.2007 15:12:02
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение ViTality »

помница когда писал свой текстовый супер редактор с БЖиШ везде советовали TCollection
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Mirage »

zub писал(а):не все операции одинаково выглядят в ундо\редо, такчто метода лучше 2


Я тоже некоторое время так думал. Но потом понял, почему все же лучше один - применить, либо отменить два и более раз подряд тогда не получится и данные не потеряются.

MiniQ писал(а):А если мне нужно взглянуть, как было 10 операций назад? Т.е. откатить назад 10 операций и потом вернуть все в текущее состояние.Вот этот патерн "первый вызов, второй вызов" как будет работать?


Собственно, для этого и делается. При применении операции вызываем Perform() и кладем её в стек. При отмене - из стека достаем, кладем в другой стек и снова вызываем Perform(). При повторении (redo) достаем из второго стека, применяем, кладем в первый.
Можно и 10 шагов откатить и накатить обратно.
Еще оба стека красиво в один массив ложатся, с индексом текущей операции. Массив просто обрезается по текущему индексу при добавлении новой операции.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение zub »

А какие проблемы могут быть с двойным вазовом? при работе не с "командой", а со стеком это сделать не получится, даже если постараться

>>Еще оба стека красиво в один массив ложатся, с индексом текущей операции. Массив просто обрезается по текущему индексу при добавлении новой операции.
у меня в конечном итоге так и получилось
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Mirage »

zub писал(а): а со стеком это сделать не получится, даже если постараться


Почему это не получится? Достал экземпляр операции из стека и вызывай её метод сколько хочешь раз.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение zub »

Если так рассуждать то можно хоть что сделать)) Множественный вызов Perform тоже ничего хорошего не сулит.
Имхо ниче доставать ненадо, надо просто делать UndoStack.Undo или UndoStack.Redo. Возня с "операцией" должна быть только на этапе ее создания и подготовки, после помещения в стек нечего к ней лезти.

Как ни крути а Perform будет универсальным (с одинаковой реализацией ундо\редо) только для простых случаев изменения данных. Например добавление\удаление элемента массива уже не такая универсальная операция.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Re: Есть какие то типовые варианты создания функции отмена?

Сообщение Mirage »

zub писал(а):Множественный вызов Perform тоже ничего хорошего не сулит.


Это как раз штатная ситуация. Потерь данных точно нет. В отличии от повторного вызова Undo.

zub писал(а):Имхо ниче доставать ненадо, надо просто делать UndoStack.Undo или UndoStack.Redo. Возня с "операцией" должна быть только на этапе ее создания и подготовки, после помещения в стек нечего к ней лезти.


Можно, конечно, коллекцию (стек) нагрузить знаниями о том, что там хранятся операции и что их нельзя отдавать, и что надо контролировать чтобы они правильно вызывались. Но это как раз не "просто делать". Тут прям напрячься надо. :lol:

zub писал(а):Как ни крути а Perform будет универсальным (с одинаковой реализацией ундо\редо) только для простых случаев изменения данных. Например добавление\удаление элемента массива уже не такая универсальная операция.


То, что он универсальный это не принципиальный момент. Может и не быть универсальным. Может хранить флажок, что делаем в следующий раз: добавляем или удаляем.
Принципиально то, что все максимально просто, вся информация в самой операции и как её не мучай, потери данных не будет.
А коллекция останется коллекцией. Её можно даже будет в любой момент заменить на другую с аналогичным интерфейсом, как и должно быть с коллекциями.
Ответить