Russian Qt Forum
Ноябрь 22, 2024, 15:15 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Undo для данных мапы  (Прочитано 13951 раз)
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #15 : Сентябрь 20, 2017, 11:02 »

А чем грозит "совпадение времени"? Ну сработает undo вхолостую, не беда
А как различать который удалять если у нас время это ключ. Поэтому удаляем и добавляем все совпадающие по времени.
пример:
было: (1:00, Data1) (2:00, Data2) (2:00, Data3) (3:00, Data4) (3:00, Data5)
стало: (1:00, Data1) (2:00, Data2) (2:00, Data3new) (3:00, Data4) (3:00, Data5)

действие:
old:  (2:00, Data2) (2:00, Data3)
new: (2:00, Data2) (2:00, Data3new)

вперед: удалить по времени из old, добавить new
назад: удалить по времени из new, добавить old

Вроде бы все просто. Или я что то не понял?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #16 : Сентябрь 20, 2017, 11:45 »

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

Когда Вам приводят пример кода, Вы только на синтаксис смотрите? Улыбающийся Кроме синтаксиса, этот вариант чем не устраивает, для решения задачи в формулировке из первого сообщения?
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Сентябрь 20, 2017, 15:05 »

вперед: удалить по времени из old, добавить new
назад: удалить по времени из new, добавить old
Так а Вы какую задачу решаете? Улыбающийся Вопрос был сохранить для undo изменение времени т.е самого ключа (а не только данных). Хотя вероятно и здесь Ваша находка (всех с тем же ключом) будет работать. Я, правду сказать, не додумался что так можно.

Кроме синтаксиса, этот вариант чем не устраивает, для решения задачи в формулировке из первого сообщения?
Юзер нажал на точку графика и потянул, т.е. drag начался. Поймав этот момент я тупо сохранил все данные для undo и закрыл его блок нафиг. Теперь на каждое перемещение точек я перестраиваю данные, сортирую, и показываю юзеру новый график. Undo меня уже совершенно не волнует, для него я все сделал.  А что будет с Вашей схемой работы?

Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #18 : Сентябрь 20, 2017, 15:42 »

Юзер нажал на точку графика и потянул, т.е. drag начался. Поймав этот момент я тупо сохранил все данные для undo и закрыл его блок нафиг. Теперь на каждое перемещение точек я перестраиваю данные, сортирую, и показываю юзеру новый график. Undo меня уже совершенно не волнует, для него я все сделал.  А что будет с Вашей схемой работы?

Надо определить набор действий, которые изменяют данные. "Юзер нажал на точку графика и потянул, т.е. drag начался." - это что за действие? Допустим "перемещение значения", примерно:
Код
C++ (Qt)
void moveValue(Storage & storage, double from_time, double value, double to_time )
{
   storage.erase(from_time);
   storage.emplace(to_time, value);
}
 
в списке команд соответственно:
Код
C++ (Qt)
   UserAction move_value{ bind(&moveValue, ref(storage), 5, 7, 9)
                        , bind(&moveValue, ref(storage), 9, 7, 5) };
   actions.push_back(move_value);
 

При перетаскивании точки графика будет возникать множество moveValue(), постоянно добавлять их в actions не надо, достаточно изменять последнее действие, которое зафиксируется при "отпускании" точки юзером. Итого добавится одна команда, полностью отменяющая перетаскивание.
Записан

Пока сам не сделаешь...
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #19 : Сентябрь 20, 2017, 17:49 »

Я бы сделал команду с 3мя значениями: ключ, список старых value, список новых value.
Если список пустой, то при undo/redo делаем erase ключа. Иначе делаем ренж-инсерт списка старых\новых значений в зависимости от undo/redo.
В случае, если мапа обычная, а не мульти, вместо списков можно хранить maybe на значение.

Если данных много, а изменений мало, то можно хранить список изменений - add/delete/update + value. Причем update == delete old + add new (т.е. есть всего 2 типа действий, но update разбиваем на 2). При redo действия выполняем слева направо, при redo - справа налево.
« Последнее редактирование: Сентябрь 20, 2017, 17:54 от Авварон » Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #20 : Сентябрь 20, 2017, 19:55 »

Вот тут идея, как обощить команды, основываясь на той же сериализации:
http://www.emodel.org.ua/index.php/uk/57-archive/2017-%D1%80%D1%96%D0%BA/39-1/997-39-1-6-u.html
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Сентябрь 21, 2017, 09:57 »

А как вообще двигать точки (даже без undo)? У меня там довольно развесисто, не мапа, но все равно есть ключ/данные. А для мапы предлагаю так
Код
C++ (Qt)
typedef QMap<double, CData> TMap;
typedef TMap::iterator TIter;
typedef QVector<TIter> TMapSelection;
 
void MoveSelection( TMap & map, TMapSelection & selection, double dx, double dy )
{
 for (int i = 0; i < selection.size(); ++i) {
   TIter & it = selection[i];
   CData temp = it.value() + dy;
   double time = it.key() + dx;
   map.erase(itime);
   it = map.insert(time, temp);
 }
}
 
Ну и как-то не вижу легкого способа встроить сюда undo. Конечно сделать можно, но выходит весьма громоздко
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Сентябрь 21, 2017, 10:08 »

При перетаскивании точки графика будет возникать множество moveValue(), постоянно добавлять их в actions не надо, достаточно изменять последнее действие, которое зафиксируется при "отпускании" точки юзером. Итого добавится одна команда, полностью отменяющая перетаскивание.
Так рекомендуют в букваре, но Undo у меня свое и "merge" там нет, ну то ладно, мои проблемы. Но так ли уж это хорошо обновлять undo на каждое движение мыша? А при exception можно еще и остаться с невалидным undo. Да и c merge еще придется пыхтеть (см selection в посте выше)
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #23 : Сентябрь 21, 2017, 10:25 »

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

При перетаскивании точки графика будет возникать множество moveValue(), постоянно добавлять их в actions не надо, достаточно изменять последнее действие, которое зафиксируется при "отпускании" точки юзером. Итого добавится одна команда, полностью отменяющая перетаскивание.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #24 : Сентябрь 22, 2017, 09:21 »

Так а Вы какую задачу решаете? Улыбающийся Вопрос был сохранить для undo изменение времени т.е самого ключа (а не только данных). Хотя вероятно и здесь Ваша находка (всех с тем же ключом) будет работать. Я, правду сказать, не додумался что так можно.
Будет. Это самый простой способ, но увеличивает объем данных на действия пользователя(перемещение).
второй способ: если ввести идентификатор, это сократит объем действий пользователя при перемещении, но увеличит объем данных.
третий способ: дополнительные данные не требуются, но дольше работает(удаление и перемещение сравнивает данные)
UserAction{ QVector<Time, Data> old, new; QVector<QPair<TimeOld, TimeNew>,Data> move }
old - мы ищем первый элемент точно с таким временем и данными и удаляем(нет разницы какой из одинаковых элементов удалять).
move - ищем первый элемент с TimeOld,Data и меняем время
new - добавляем(тут просто)
для операции "вперед" вначале удаляем old, потом перемещаем(возможно надо запомнить перемещенные элементы и не перемещать их второй раз, хотя имхо и без этого будет работать), потом добавляем
операция назад наоборот удаляем new, перемещаем move, добавляем old
p.s. хотя возможно порядок не важен.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #25 : Сентябрь 22, 2017, 09:28 »

первый способ оптимален когда: много данный, мало действий пользователя(данные на часто пересекаются по времени)
второй: по сути тоже самое что и третий(жрет больше данный но быстрее ищет), вместо полного сравнивания структуры Data будут сравниваться идентификаторы.
третий: если будет очень много данных с одинаковым временем, будет долго работать. Особенно если struct Data много весит.
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.152 секунд. Запросов: 23.