Есть какие то типовые варианты создания функции отмена?
Модератор: Модераторы
Есть какие то типовые варианты создания функции отмена?
Функция Отмена последних действий иногда очень полезная, но понятия не имею какими методами ее можно организовать в программах.
Если вся программа построена на классах наследованных от TObject например, то в каждом случае надо самому все реализовывать или есть какие то средства для "сливания" предыдущих значений памяти в хранилище отдельное?
Если вся программа построена на классах наследованных от TObject например, то в каждом случае надо самому все реализовывать или есть какие то средства для "сливания" предыдущих значений памяти в хранилище отдельное?
Re: Есть какие то типовые варианты создания функции отмена?
Реализовывать нужно самому.
Например хранить отдельно "старые" объекты и новые.
Например хранить отдельно "старые" объекты и новые.
Re: Есть какие то типовые варианты создания функции отмена?
MiniQ писал(а):Например хранить отдельно "старые" объекты и новые.
Я что то зациклился на мысли о хранении значения переменных, полностью отдельно объект и правда проще слить. Спасибо.
Re: Есть какие то типовые варианты создания функции отмена?
Я стараюсь хранить минимально возможный набор данных для отката - сохранять целый объект накладно, особенно при возможности массированых изменений. Вообще тема сложная и индивидуальная - единого решения нет.
Совет - undo\redo нужно вводить какможно раньше (ну или хотябы продумать как оно будет), внедрять это хозяйство в уже рабочий код - та еще каторга
Совет - undo\redo нужно вводить какможно раньше (ну или хотябы продумать как оно будет), внедрять это хозяйство в уже рабочий код - та еще каторга
Re: Есть какие то типовые варианты создания функции отмена?
Есть такое слово, как сериализация, оно поддерживается наследниками TPersistent.
Если логика работы представлена в виде дерева наследников TPersistent, которые пишут лог своих изменений, то возможно построение функции записи макроса работы программы, и макроса текущего состояния.
Сам подумываю над таким компонентом.
Если логика работы представлена в виде дерева наследников TPersistent, которые пишут лог своих изменений, то возможно построение функции записи макроса работы программы, и макроса текущего состояния.
Сам подумываю над таким компонентом.
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Re: Есть какие то типовые варианты создания функции отмена?
Есть паттерн, сильно облегчающий реализацию undo/redo, а также дающий доп. плюшки:
Каждый тип операции модификации данных (коих по идее немног - изменение свойств чего-то, модификация данных и т.п.) оборачивается в класс с одним методом - Perform() допустим.
Первый его вызов совершает модификацию данных, второй - отменяет. Третий опять совершает и т.д.
Как это делается - сериализацией или как-то по-другому уже другой вопрос. Зависит.
И да, желательно сразу так делать, хотя, если программа написана вменяемо, то выделить классы операций должно быть несложно и уже существующем коде.
Каждый тип операции модификации данных (коих по идее немног - изменение свойств чего-то, модификация данных и т.п.) оборачивается в класс с одним методом - Perform() допустим.
Первый его вызов совершает модификацию данных, второй - отменяет. Третий опять совершает и т.д.
Как это делается - сериализацией или как-то по-другому уже другой вопрос. Зависит.
И да, желательно сразу так делать, хотя, если программа написана вменяемо, то выделить классы операций должно быть несложно и уже существующем коде.
Re: Есть какие то типовые варианты создания функции отмена?
>>оборачивается в класс с одним методом - Perform() допустим.
не все операции одинаково выглядят в ундо\редо, такчто метода лучше 2
не все операции одинаково выглядят в ундо\редо, такчто метода лучше 2
Re: Есть какие то типовые варианты создания функции отмена?
Mirage писал(а):Первый его вызов совершает модификацию данных, второй - отменяет. Третий опять совершает и т.д.
Что-то мудрено. А если мне нужно взглянуть, как было 10 операций назад? Т.е. откатить назад 10 операций и потом вернуть все в текущее состояние.
Вот этот патерн "первый вызов, второй вызов" как будет работать?
- Лекс Айрин
- долгожитель
- Сообщения: 5723
- Зарегистрирован: 19.02.2013 16:54:51
- Откуда: Волгоград
- Контактная информация:
Re: Есть какие то типовые варианты создания функции отмена?
MiniQ писал(а):Что-то мудрено. А если мне нужно взглянуть, как было 10 операций назад?
Думаю, проще сделать ссылку на следующее/предыдущее изменение. (то есть, использовать список операций)
Re: Есть какие то типовые варианты создания функции отмена?
помница когда писал свой текстовый супер редактор с БЖиШ везде советовали TCollection
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Re: Есть какие то типовые варианты создания функции отмена?
zub писал(а):не все операции одинаково выглядят в ундо\редо, такчто метода лучше 2
Я тоже некоторое время так думал. Но потом понял, почему все же лучше один - применить, либо отменить два и более раз подряд тогда не получится и данные не потеряются.
MiniQ писал(а):А если мне нужно взглянуть, как было 10 операций назад? Т.е. откатить назад 10 операций и потом вернуть все в текущее состояние.Вот этот патерн "первый вызов, второй вызов" как будет работать?
Собственно, для этого и делается. При применении операции вызываем Perform() и кладем её в стек. При отмене - из стека достаем, кладем в другой стек и снова вызываем Perform(). При повторении (redo) достаем из второго стека, применяем, кладем в первый.
Можно и 10 шагов откатить и накатить обратно.
Еще оба стека красиво в один массив ложатся, с индексом текущей операции. Массив просто обрезается по текущему индексу при добавлении новой операции.
Re: Есть какие то типовые варианты создания функции отмена?
А какие проблемы могут быть с двойным вазовом? при работе не с "командой", а со стеком это сделать не получится, даже если постараться
>>Еще оба стека красиво в один массив ложатся, с индексом текущей операции. Массив просто обрезается по текущему индексу при добавлении новой операции.
у меня в конечном итоге так и получилось
>>Еще оба стека красиво в один массив ложатся, с индексом текущей операции. Массив просто обрезается по текущему индексу при добавлении новой операции.
у меня в конечном итоге так и получилось
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Re: Есть какие то типовые варианты создания функции отмена?
zub писал(а): а со стеком это сделать не получится, даже если постараться
Почему это не получится? Достал экземпляр операции из стека и вызывай её метод сколько хочешь раз.
Re: Есть какие то типовые варианты создания функции отмена?
Если так рассуждать то можно хоть что сделать)) Множественный вызов Perform тоже ничего хорошего не сулит.
Имхо ниче доставать ненадо, надо просто делать UndoStack.Undo или UndoStack.Redo. Возня с "операцией" должна быть только на этапе ее создания и подготовки, после помещения в стек нечего к ней лезти.
Как ни крути а Perform будет универсальным (с одинаковой реализацией ундо\редо) только для простых случаев изменения данных. Например добавление\удаление элемента массива уже не такая универсальная операция.
Имхо ниче доставать ненадо, надо просто делать UndoStack.Undo или UndoStack.Redo. Возня с "операцией" должна быть только на этапе ее создания и подготовки, после помещения в стек нечего к ней лезти.
Как ни крути а Perform будет универсальным (с одинаковой реализацией ундо\редо) только для простых случаев изменения данных. Например добавление\удаление элемента массива уже не такая универсальная операция.
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Re: Есть какие то типовые варианты создания функции отмена?
zub писал(а):Множественный вызов Perform тоже ничего хорошего не сулит.
Это как раз штатная ситуация. Потерь данных точно нет. В отличии от повторного вызова Undo.
zub писал(а):Имхо ниче доставать ненадо, надо просто делать UndoStack.Undo или UndoStack.Redo. Возня с "операцией" должна быть только на этапе ее создания и подготовки, после помещения в стек нечего к ней лезти.
Можно, конечно, коллекцию (стек) нагрузить знаниями о том, что там хранятся операции и что их нельзя отдавать, и что надо контролировать чтобы они правильно вызывались. Но это как раз не "просто делать". Тут прям напрячься надо.
zub писал(а):Как ни крути а Perform будет универсальным (с одинаковой реализацией ундо\редо) только для простых случаев изменения данных. Например добавление\удаление элемента массива уже не такая универсальная операция.
То, что он универсальный это не принципиальный момент. Может и не быть универсальным. Может хранить флажок, что делаем в следующий раз: добавляем или удаляем.
Принципиально то, что все максимально просто, вся информация в самой операции и как её не мучай, потери данных не будет.
А коллекция останется коллекцией. Её можно даже будет в любой момент заменить на другую с аналогичным интерфейсом, как и должно быть с коллекциями.
