n
nklyOct. 17, 2022, 11:40 a.m.

Как сохранить данные древовидной модели на основе QStandardItemModel в файл

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

Что такое модель данных? Хотелось бы по-подробнее, с примерами, простыми словами. В одной статье при попытке объяснить что такое модель встретил такую фразу "Ваши данные - это и есть модель. Используйте их". Очень информативно :)))

Хотелось бы по-подробнее узнать сферу применения моделей, какие преимущества они дают, а где лучше их не использовать?

Что такое "источник данных"? Например если мы в программе считываем содержимое текстового файла в QStringList list что является источником файл или list?
Что может быть источником данных? База данных, файл, QStringList, QVector и т.д. Какие-еще могут быть варианты?

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

Когда возникает тот или иной сигнал и каким из них лучше воспользоваться в той или иной ситуации.

И самое для меня важное: каковы алгоритмы заполнения ДРЕВОВИДНЫХ моделей данными из "источника данных" и как затем эти измененные данные записать обратно в "источник данных".

Может быть уже есть такие материалы, а я просто не знаю, тогда подскажите где почитать.
Я пытался искать на https://doc.qt.io, и в книжке Макса Шлее, а в книжке Марка Саммерфилда например написано: "Методы load() и save() служат для загрузки и сохранения данных при-
ложения; мы их не приводим".
Видимо их реализация элементарна :)))

Интернет-поиск дает десятки, сотни ссылок на статьи о том как работать с моделями, но практически все они описавают одни и те же примеры как создать модель списка или таблицы, но не дерева вложенности N и нигде не рассматриваются вопросы заполнения модели данными и сохранения данных из модели после ее редактирования. Максимум рассматриваются примеры работы с базой данных, но это таблица, а про ДЕРЕВО вложенности N ничего нет.

Ну это были мои хотелки, а теперь собственно и вопрос.

Я пишу приложение с использованием QStandardItemModel и QTreeView.
В QTreeView мне нужно отображать дерево элементов со степенью вложенности N. Ну хотя-бы N=5. Всего элементов будет до 500. Данные для отображения хранятся в текстовом файле.
Вот как описывается каждый элемент дерева в моем файле:

{
node:нода 1-2
parent:node1
Text:
текст ноды 1-2
}

node: название элемента
parent: название элемента-родителя
Text: здесь может быть, а может и не быть какой-то нужный мне текст

Я создал модель на основе QStandardItemModel, худо-бедно написал функцию заполняющую ее данными, в представлении QTreeView я могу добавлять элементы, переименовывать, перетаскивать. Но после этого мне нужно сохранить данные обратно в файл. Вот с этим возникла проблема.

Я рассуждаю примерно так:
Нужно перебрать в цикле все элементы модели (items) и для каждого из них записать в файл название элемента и измененные данные о его родителе, если родителя например переименовали, или элемент поменял родителя при перетаскивании.
Но как перебрать все элементы модели? Не могу ничего придумать.
Может нужен какой-то другой алгоритм?

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

6
МЛ
  • Oct. 17, 2022, 12:26 p.m.

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

    n
    • Oct. 17, 2022, 1:10 p.m.

    Структуру я придумал сам, она может быть другой. Но тогда нужно будет переписывать функцию, которая заполняет модель. Я потратил на написание этой функции кучу времени.
    Зачем хранить в программе изменения, ведь они есть в модели?
    В программе я считываю файл в QStringList и модель заполняется уже из него. Меня устроил бы вариант когда я полностью перезаписываю этот QStringListl данными из модели, а потом записываю его в файл поверх старого содержимого.
    Проблема в том как достать из модели данные по всем элементам.

      МЛ
      • Oct. 17, 2022, 2:07 p.m.

      у QStandartModelItem есть фунции index, data и hasChildren. в цикле бегаете по веткам рекурсивно. вообще пооцесс обратный заполнению. как вы в модель когда писали, искали нужного родителя? можно код функции в студию.

        n
        • Oct. 18, 2022, 1:54 a.m.
        • (edited)

        Привожу код функции построения дерева элементов.
        full_list это текст считанный из файла. Он содержит всю информацию о дереве и другие данные.
        ui->txtDbg это окошко которое я добавил для отладки, я пишу туда отладочные сообщения.
        oneNoda - это как бы объект элемента.
        Функция просто перебирает в QStringList все элементы по порядку, анализирует имя элемента, и кто у него родитель и просто добавляет итем к родителю.
        Кстати обратите внимание на строки 24 и 25. В одном случае мы добавляем итемы к корневому элементу root и получается что в модели один элемент root с дочерними элементами. А в другом случае каждый итем добавляется в модель. Результат в обоих случаях выглядит одинаково, но как надо делать правильно?
        Не могу понять как запрограммировать в функции процесс обратный процессу построения дерева. Если можно накидайте хотя-бы каркас.

        void tetr::build_tree()
        {
            QStringList node_name_list=full_list->filter("node:");
            QStringList roditel_name_list=full_list->filter("parent:");
            struct Noda {
                QString noda_name;
                QString roditel_name;
            };
        
            if(node_name_list.size()!=roditel_name_list.size()){
                ui->txtDbg->append("WARNING!!! node_name_list.size != roditel_name_list.size");
                return;
            }
        
            Noda oneNoda;
                for(int i=0;i<node_name_list.size();i++){
                    oneNoda.noda_name=node_name_list.at(i).section(':',1,1);
                    oneNoda.roditel_name=roditel_name_list.at(i).section(':',1,1);
                    QStandardItem *item=new QStandardItem(oneNoda.noda_name);
                    item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled);
                    QList <QStandardItem*>list=model->findItems(oneNoda.roditel_name,Qt::MatchExactly|Qt::MatchRecursive);
        
                        if(oneNoda.roditel_name=="root"){   //если элемент корневой, добавляем его в модель.
                           //model->appendRow(item);
                           root->appendRow(item);
                        }
                        //проверка количества найденных элементов-родителей
                        if(list.size()>1){
                            ui->txtDbg->append("В модели найдено более одного элемента с данным именем.");
                            for(int i=0;i<list.size();i++){
                               ui->txtDbg->append(list[i]->data().toString());
                            }
                        }
        
                        if(list.size()==1){
                            //ui->txtDbg->append("Для элемента \""+oneNoda.noda_name+"\" в модели найден единственный элемент-родитель \""+list[0]->data().toString()+"\"");
                            list[0]->appendRow(item);
                        }
                        if(list.size()==0 && oneNoda.roditel_name!="root"){//если элемент не найден И это не элемент "root"
                            //(элемента root действительно нет. Он указан как родитель верхнего уровня
                            ui-> txtDbg->append("Для элемента \""+oneNoda.noda_name+"\" в модели отсутствует элемент-родитель \""+oneNoda.roditel_name+"\"");
                        }
            }
        
            node_name_list.clear();
            roditel_name_list.clear();
        }
        
        
          МЛ
          • Oct. 18, 2022, 4:35 a.m.

          Зачем вы тогда храните в файле номера нодов и родителей, если вы ищите родителя в своей модели по имени? При таком раскладе конечно можно найти несколько родителей, а кто настоящий то?
          Я так понимаю

          node:node 1-2
          parent:node1
          Text:
          текст ноды 1-2
          

          в наименовании node 1-2 вы уже храните и индекс родителя и индекс нода, тоесть node 1-2 это 2ой потомок node1.

          Если вы создаете QStandartItem а потом добавляете его в QTreeWidget, то он все равно это все добавляет в модель. Пишите сразу в модель через setData.

            n
            • Oct. 18, 2022, 10:14 a.m.

            Вы меня неправильно поняли. Допустим я собираю кулинарные рецепты и один из них - рецепт супа Харчо. Структура файла данных такова:

                {
                node:Рецепт супа Харчо
                parent:Вкусные блюда, которые мне нравятся
                Text:
                Нужно взять все необходимые продукты и приготовить суп Харчо. Суп Харчо очень вкусный
                Я очень его люблю!!!
                }
            

            Если вы создаете QStandartItem а потом добавляете его в QTreeWidget, то он все равно это все добавляет в модель.

            Не могли бы Вы выразиться более понятно. Кто "он" все равно добавляет все это в модель? QStandardItem добавляет или QTreeWidget добавляет? Каким образом "он" добавляет это в модель? Где эта функция?
            Я использую QTreeView а не QTreeWidget.

            Давайте забудем пока о функции build_tree. Я сделал ее как мог и она записывает данные в модель и они правильно отображаются.
            Вернемся к началу;
            У меня есть модель MyModel model. Она содержит всю необходимую информацию. Мне нужно перебрать все итемы в модели и каждый записать в QStringList full_list.
            Для этого мне нужно создать функцию которая это будет делать, возможно с использованием функции setData()
            Должно получиться что-то вот такое

            void tetr::write_data_from_model_to_full_list()
            {
                for("тип" i="что-то";i<="еще_что-то";i++) //перебираем все итемы модели
                {   
                    QModelIndex ind=<что-то>; //вычисляем индекс для i-того итема
                    QStandardItem *item=model->itemFromIndex(ind);// получаем итем по индексу
                    QString str=item->data(Qt::DisplayRole).toString(); //получаем имя итема
                    full_list.append(str);   //записываем текст в QStringList full_list который затем будем записывать в файл
            
                }
            }
            

            Что использовать вместо "что-то" и "еще_что-то"? Вот в этом моя проблема.

            Алгоритм предложенный мной для функции write_data_from_model_to_full_list() прост и понятен. Но как перебрать все итемы модели. Может быть нужно использовать какой-то другой алгоритм переноса данных из модели в файл?

              Comments

              Only authorized users can post comments.
              Please, Log in or Sign up
              Дмитрий

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:60points,
              • Rating points-1
              Дмитрий

              C++ - Тест 003. Условия и циклы

              • Result:92points,
              • Rating points8
              d
              • dsfs
              • April 26, 2024, 4:56 a.m.

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:80points,
              • Rating points4
              Last comments
              k
              kmssrFeb. 8, 2024, 6:43 p.m.
              Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
              Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
              EVA
              EVADec. 25, 2023, 10:30 a.m.
              Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
              J
              JonnyJoDec. 25, 2023, 8:38 a.m.
              Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
              G
              GvozdikDec. 18, 2023, 9:01 p.m.
              Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
              Now discuss on the forum
              G
              George13May 7, 2024, 12:27 a.m.
              добавить qlineseries в функции в функции: "GPlotter::addSeries(QString title, QVector &arr)" я вызываю метод setChart(...), я в конструктор передал адрес на QChartView элемент
              BlinCT
              BlinCTMay 5, 2024, 5:46 a.m.
              Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
              PS
              Peter SonMay 3, 2024, 5:57 p.m.
              Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
              Evgenii Legotckoi
              Evgenii LegotckoiMay 2, 2024, 2:07 p.m.
              Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
              IscanderChe
              IscanderCheApril 30, 2024, 4:22 a.m.
              Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

              Follow us in social networks