Глава 18 · История и документ

Повтор действий (Redo)

Redo — второй стек рядом с Undo. Новое действие после отмены должно его опустошить.

Redo — второй стек, а не «отмена отмены»

Раздел 18.24 отменяет действие, снимая его с undo_stack. Чтобы вернуть его назад, само действие нужно куда-то временно положить — во второй стек, redo_stack:

redo.py
def redo(self):
    if not self.redo_stack:
        return
    shapes = self.redo_stack.pop()
    self.document.extend(shapes)
    self.undo_stack.append(shapes)
    self.render_document()
Реальное окно: прямоугольник, ранее убранный через Undo, снова виден на холсте после Redo
Реальное окно: после Ctrl+Y — действие, отменённое в разделе 18.24, восстановлено.

Новое действие обязано опустошить redo_stack

Если после Undo пользователь рисует что-то НОВОЕ, старая ветка «которую можно было бы повторить» перестаёт иметь смысл — вернуть её означало бы применить действие к документу, который уже стал другим. Поэтому _commit_action() (раздел 18.24) всегда очищает redo_stack:

commit_ochischaet_redo.py
def _commit_action(self, shapes):
    self.document.extend(shapes)
    self.undo_stack.append(shapes)
    self.redo_stack.clear()   # новое действие делает старую ветку redo недействительной
    self.render_document()
Забытый redo_stack.clear() — незаметная, но реальная ошибка
Без этой строки Redo мог бы «воскресить» фигуру, которая никак не связана с текущим состоянием документа — потому что после Undo пользователь успел нарисовать что-то ещё, а старое отменённое действие всё ещё лежит в очереди «повторить». Раздел 18.31 разбирает этот случай как отдельный Debug Lab.
Практика: стек повтора и его очистка новым действием
Автоматическая проверка — redo восстанавливает действие, новое действие обнуляет redo
Открыть практику →