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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Undo для данных мапы  (Прочитано 13113 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Сентябрь 15, 2017, 16:43 »

Добрый день

Есть скромные данные в мапе упорядоченные по ключу "время" (double). Данные показываются в виде графика, юзер может менять как данные так и ключ таская точки по вертикали и/или горизонтали. Конечно когда время изменилось данные удаляются и вставляются снова - теперь они уже в следуют в др порядке.

Как сохранить undo перед активностью юзера? Приделывать "уникальное ID" ну очень не хотелось бы

Спасибо
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


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


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

memento как вариант.
сериализировать все ключи и значения после каждого изменения.
Записан

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 не волк, в лес не уйдёт
deMax
Хакер
*****
Offline Offline

Сообщений: 600



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

Есть паттерн команда. Когда изменяете что то на графике создаете команду(сдвинуть точку туда то, удалить(с запоминанием что было), создать...) и эта команда меняет данные в вашем Qmap. Тогда будет легко пройтись по изменениям.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

memento как вариант.
сериализировать все ключи и значения после каждого изменения.
Да, тоже не вижу ничего лучшего

Есть паттерн команда. Когда изменяете что то на графике создаете команду(сдвинуть точку туда то, удалить(с запоминанием что было), создать...) и эта команда меняет данные в вашем Qmap. Тогда будет легко пройтись по изменениям.
Команла - не команда... для undo что сохранять?
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



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

Команла - не команда... для undo что сохранять?
Разницу между что было и что стало, список действий: Удалили такие то ключи(с содержимым), добавили такие, изменили такие(старое содержимое). Тогда undo будет тоже самое что и обычные действия пользователя(только команда будет инвертирована).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Разницу между что было и что стало, список действий: Удалили такие то ключи(с содержимым), добавили такие, изменили такие(старое содержимое). Тогда undo будет тоже самое что и обычные действия пользователя(только команда будет инвертирована).
Во как хорошо с "паттернами" Улыбающийся Вникать в задачу, думать - та зачем? Лепи по образцу - и все дела! Только вот почему-то частенько так не выходит, напр в данном случае не вижу как мне "инвертировать" время - как же undo найдет эл-т что был изменен?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



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

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

Undo и не должен ничего искать, это команда/список команд, которые изменяют данные.

Лепи по образцу - и все дела!

Именно так: по образцу. Благо их в интернетах полно. Надо только почитать.
Записан

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

Сообщений: 11445


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

Undo и не должен ничего искать, это команда/список команд, которые изменяют данные.
Так в том и вопрос: какие (или которые) данные? Не вижу каким образом undo перепишет время/данные именно того эл-та что был изменен.

Именно так: по образцу. Благо их в интернетах полно. Надо только почитать.
Ага, сейчас все на уровне "почитай". Чего там думать, осмысливать - сожрал очередную "ссылочку", вот и все.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



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

юзер может менять как данные так и ключ таская точки по вертикали и/или горизонтали

Эти данные какими методами/функциями меняются в коде? Вот их в команды и записывайте.

Ага, сейчас все на уровне "почитай". Чего там думать, осмысливать - сожрал очередную "ссылочку", вот и все.

И в чём проблема сожрать очередную ссылочку и осмыслить её применимость к поставленной задаче? Или Вы хотите чтобы другие за Вас жевали? Улыбающийся
Записан

Пока сам не сделаешь...
deMax
Хакер
*****
Offline Offline

Сообщений: 600



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

Как сохранить undo перед активностью юзера? Приделывать "уникальное ID" ну очень не хотелось бы
ну если время уникально, то ориентироваться на время (удаляем такие то ключи, добавляем такие). Время это ключ, изменение это тоже самое что и удалить+добавить.
если время не уникально то только добавлением id. Можно было бы запоминать номер по порядку какой элемент нужно удалить, но он же будет сортировать всегда по разному(и с одинаковым ключом элементы будут меняться местами, а если и данные одинаковы).
имхо оптимальный вариант запоминать по дате, а для элементов с одинаковым временем создавать backup.(имхо оптимально)
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



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

на самом деле проще: если удаляете то удаляйте все элементы с таким же временем и потом их добавляете.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

ну если время уникально, то ориентироваться на время (удаляем такие то ключи, добавляем такие). Время это ключ, изменение это тоже самое что и удалить+добавить.
Здесь конкретный вопрос (а не "принципиальные основы"). Думал так: записать новое время + старое время. Тогда undo по "новому" найдет эл-т, изменит время на "старое" и пересортирует. Вроде должно работать, но как-то подозрительно... И нужно новое время иметь на момент undo, это не всегда так уж просто

если время не уникально то только добавлением id. Можно было бы запоминать номер по порядку какой элемент нужно удалить, но он же будет сортировать всегда по разному(и с одинаковым ключом элементы будут меняться местами, а если и данные одинаковы).
имхо оптимальный вариант запоминать по дате, а для элементов с одинаковым временем создавать backup.(имхо оптимально)
Вы можете излагать яснее? "Запоминать по дате", "создавать backup" - хз что Вы имели ввиду. Уникально время или нет - я не знаю (задачу я упрощенно изложил, в действительности там куда больше всего). Возможно Вы имели ввиду что записывать индекс эл-та не проходит. Не уверен. Ну да, сортировка одинаковые расставит как хочет, и что, чем это помешает undo записать новый индекс? Правда тогда undo надо делать уже после вставки, что еще извращеннее...

И в чём проблема сожрать очередную ссылочку и осмыслить её применимость к поставленной задаче?
Э нет, ничего осмысливать жрущий уже не будет, просто времени на это уже не останется,  ведь надо сожрать как можно больше Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



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

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

Код
C++ (Qt)
using Action = function<void()>;
 
struct UserAction
{
   Action redo;
   Action undo;
};
 
using Storage = map<double, double>;
 
void print(const Storage & storage)
{
   cout << "{ ";
   for (auto value:storage)
       cout << "{" << value.first << ", " << value.second << "}, ";
   cout << " }" << endl;
}
 
void addValue(Storage & storage, double time, double value)
{
   storage.emplace(time, value);
}
 
void removeValue(Storage & storage, double time)
{
   storage.erase(time);
}
 
void testUndoRedo()
{
   cout << "initial storage:" << endl;
   Storage storage;
 
   addValue(storage, 5, 7);
   addValue(storage, 6, 8);
   print(storage);
 
   cout << "user actions:" << endl;
   vector<UserAction> actions;
 
   UserAction add_value{ bind(&addValue, ref(storage), 7, 9)
                       , bind(&removeValue, ref(storage), 7) };
   actions.push_back(add_value);
   (*actions.rbegin()).redo();
   print(storage);
 
   UserAction add_other_value{ bind(&addValue, ref(storage), 6.5, 4)
                             , bind(&removeValue, ref(storage), 6.5) };
   actions.push_back(add_other_value);
   (*actions.rbegin()).redo();
   print(storage);
 
   UserAction remove_value{ bind(&removeValue, ref(storage), 6)
                          , bind(&addValue, ref(storage), 6, storage.at(6)) };
   actions.push_back(remove_value);
   (*actions.rbegin()).redo();
   print(storage);
 
   cout << "undo user actions:" << endl;
   for (auto i = actions.rbegin(); i != actions.rend(); ++i)
   {
       (*i).undo();
       print(storage);
   }
 
   cout << "redo user actions:" << endl;
   for (auto i = actions.begin(); i != actions.end(); ++i)
   {
       (*i).redo();
       print(storage);
   }
}
 
int main()
{
   testUndoRedo();
 
   return 0;
}
 
код на ideone

Понятное дело что всплывут особенности по которым этот вариант не подойдёт, но всё же... скромные данные в мапе меняются, откатываются и накатываются.
Записан

Пока сам не сделаешь...
deMax
Хакер
*****
Offline Offline

Сообщений: 600



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

Здесь конкретный вопрос (а не "принципиальные основы"). Думал так: записать новое время + старое время. Тогда undo по "новому" найдет эл-т, изменит время на "старое" и пересортирует. Вроде должно работать, но как-то подозрительно... И нужно новое время иметь на момент undo, это не всегда так уж просто
А если новое и старое время будет с кем то совпадать? городить логику?
Код:
struct Data{}
struct UserAction { QMap<Time, Data> oldData, newData; }
Если время удаляемых данных совпадает с другими данными, то удаляем их тоже, а потом добавим. Если вам нужно знать что такой то элемент изменился(анимацию например показать), тогда:
Код:
struct UserAction { QMap<Time, Data> oldData, newData; QVector<QPair<int,int>> moveData; } // moveData содержит позицию в oldData и newData для элементов которые изменились.
Тут предлагали бекапить весь массив на каждой итерации, я предлагаю бекапить изменения(причем все данные с таким же временем тоже бекапить, что бы не городить логику). Вроде все просто или я чего то не понял?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

ViTech, спасибо за приятную демонстрацию современного сынтаксыса, но меня интересует алгоритм/принцип, можно просто словами, напр так
Думал так: записать новое время + старое время. Тогда undo по "новому" найдет эл-т, изменит время на "старое" и пересортирует. Вроде должно работать, но как-то подозрительно... И нужно новое время иметь на момент undo, это не всегда так уж просто

А если новое и старое время будет с кем то совпадать? городить логику?
А чем грозит "совпадение времени"? Ну сработает undo вхолостую, не беда
Тут предлагали бекапить весь массив на каждой итерации, я предлагаю бекапить изменения(причем все данные с таким же временем тоже бекапить, что бы не городить логику). Вроде все просто или я чего то не понял?
Если "некоторые" (не все) то undo должно сначала вырезать данные время которых изменилось (а потом вставить запомненное).

Тут полазил по коду - к сожалению, нет, ключ не уникален. Напр копирование делается так: дублятся выбранные точки и юзер таскает этот дубликат. Когда мыша отпущена удаляются точки для которых ключ И ДАННЫЕ одинаковы.

В общем, впечатление такое что, наверное, можно, но уж слишком "хитро-делано" выходит. Наверное стоит остановиться на туповатом но простом и надежном варианте "сохранить всех"
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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