Виталий Антипов
Виталий Антипов21 лютого 2018 р. 09:54

Проблема с ComboBox

Здравствуйте! Столкнулся со следующей проблемой. Есть кастомная таблица из ListView, в делегате которого содержится ComboBox. ComboBox заполняется изменяемой моделью данных, которая является результатом sql запроса. Так же ComboBox имеет свойство editable: true и значение editText отправляется в sql запрос для фильтрации данных. Другими словами этот ComboBox является фильтром. Проблема в том, что если количество строк ListView (а соответственно и количество ComboBox'ов) > 1, то изменение модели в одном ComboBox'е приводит к изменению модели в другом и значение editText в ранее использованном ComboBox'е меняется. Вопрос следующий: как убрать привязку editText к модели или как клонировать существующую модель, чтобы отвязаться от ее будущих данных?

ListView {
                    id: list
                    ...
                    model: inputkolopor.currentText
                    delegate: component
                }
                        Component {
                            id: component
                            Item {
                                id: item0
                ...
                    Rectangle {
                        id: rec03_02
                        ...
                        ComboBox {
                            id: combo_obRU
                            property string id: ""
                            ...
                            editable: true
                            textRole: 'podsh_obRU'
                            delegate: ItemDelegate {
                                width: combo_obRU.width
                                text: combo_obRU.textRole ? (Array.isArray(combo_obRU.model) ? modelData[combo_obRU.textRole] : model[combo_obRU.textRole]) : modelData
                                highlighted: combo_obRU.highlightedIndex === index
                            }
                            onCurrentTextChanged: {
                                if(currentIndex==-1){
                                    combo_obRU.id = ""
                                } else {
                                    combo_obRU.id = model_podsh.getId(currentIndex)
                                }
                            }
                        }
                        Button {
                            id: but_obRU
                            ...
                            onClicked: {
                                stackView.obRU = combo_obRU.editText
                                qmlFilterBearing()
                                combo_obRU.model = model_podsh
                                combo_obRU.popup.visible = true
                            }
                        }
                    }                   
                            }
                        }
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

15
Evgenii Legotckoi
  • 21 лютого 2018 р. 10:01

Добрый день.

Как я понимаю все ComboBox`ы используют одну и ту же модель данных. Фактически, вам нужно собственную модель данных для каждого ComboBox`а.
Я правильно понимаю, что Вы использовали модель для фильтрации ту, что зарегистрирована через регистрацию Контекста? То есть через setContextProperty?

Если так, то я бы предложил Вам несколько иное решение, но мне его нужно дома смотреть, сейчас у меня нет кода под рукой.
Можно создать свою модель данных для каждого ComboBox в делегате. Тогда все КомбоБоксы будут независимы друг от друга.
    Виталий Антипов
    • 21 лютого 2018 р. 10:17

    Спасибо за ответ! Да, модель передаю через

    engine.rootContext()->setContextProperty("model_podsh", model_podsh);
    Иметь собственную модель для каждого ComboBox'а - первое что приходит на ум, но не очень понятно как передать модели. Попробовал решить в лоб:
    Button {
                                id: but_obRU
                                property int index_: index
                                ...
                                onClicked: {
                                    stackView.obRU = combo_obRU.editText
                                    qmlFilterBearing()
                                    if(index_==0){
                                    combo_obRU.model = model_podsh0
                                    }
                                    if(index_==1){
                                    combo_obRU.model = model_podsh1
                                    }
                                    if(index_==2){
                                    combo_obRU.model = model_podsh2
                                    }
                                    if(index_==3){
                                    combo_obRU.model = model_podsh3
                                    }
                                    if(index_==4){
                                    combo_obRU.model = model_podsh4
                                    }
                                    if(index_==5){
                                    combo_obRU.model = model_podsh5
                                    }
                                    if(index_==6){
                                    combo_obRU.model = model_podsh6
                                    }
                                    if(index_==7){
                                    combo_obRU.model = model_podsh7
                                    }
    } } 
    Результат тот-же, модель одна на всех.
      Evgenii Legotckoi
      • 21 лютого 2018 р. 10:25

      Нет. Это явно неправильное решение. К тому же, у вас может быть бесконечное число строк, а следовательно такое решение просто не подходит, не говоря уж о том, что оно неприемлемо для продакшена)))
      Когда буду дома, посмотрю код и скину возможный вариант создания отдельных моделей.

        Виталий Антипов
        • 21 лютого 2018 р. 11:35

        Буду ждать с нетерпением )

          Evgenii Legotckoi
          • 21 лютого 2018 р. 15:52

          В общем идея такая. Нужно написать класс, который будет отвечать за некоторую таблицу, как раз Ваша модель должна получиться.

          Я вам покажу пример, который может в данном случае использоваться.

          ResultsModel.h
          #pragma once
          
          #include <QSqlQueryModel>
          
          class ResultsModel : public QSqlQueryModel
          {
              using BaseClass = QSqlQueryModel;
          
              Q_OBJECT
          public:
              explicit ResultsModel(QObject* parent = nullptr);
          
              enum Roles
              {
                  IdRole = Qt::UserRole + 1,
                  NameRole,
                  TotalScoreRole,
                  TimeRole,
                  DateRole,
              };
          
              QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
          
          protected:
              QHash<int, QByteArray> roleNames() const;
          
          signals:
          
          public slots:
              void updateModel();
              int getId(int row);
          };
          ResultsModel.cpp
          #include "ResultsModel.h"
          
          ResultsModel::ResultsModel(QObject *parent) :
              BaseClass(parent)
          {
              updateModel();
          }
          
          QVariant ResultsModel::data(const QModelIndex &index, int role) const
          {
              int columnId = role - Qt::UserRole - 1;
              QModelIndex modelIndex = this->index(index.row(), columnId);
              return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
          }
          
          QHash<int, QByteArray> ResultsModel::roleNames() const
          {
              QHash<int, QByteArray> roles;
              roles[IdRole] = "gamer_id";
              roles[NameRole] = "name";
              roles[TotalScoreRole] = "total_score";
              roles[TimeRole] = "time";
              roles[DateRole] = "date";
              return roles;
          }
          
          void ResultsModel::updateModel()
          {
              setQuery(QString("SELECT table_name FROM %1 ORDER BY total_score DESC;"));
          }
          
          int ResultsModel::getId(int row)
          {
              return data(this->index(row, 0), IdRole).toInt();
          }
          

          Дальше нужно зарегистрировать эту модель как тип данных QML
          qmlRegisterType<ResultsModel>("SQLHelper", 1, 0, "ResultsModel");

          Далее импортируем этот модуль SQLHelper в QML файле и используем эту модель из него в делегате
          import Arkanoid 1.0
          
          ...
          ComboBox {
              id: combo_obRU
          
              model: ResultsModel { id: comboBoxModel } // Вот это использование модели
          
          }
          ...
          Практически в каждом делегате будет своя модель данных. И они должны будут быть независимы друг от друга и будут иметь собственную выборку.
          Попробуйте такой вариант, полагаю, что это должно помочь Вам.

            Виталий Антипов
            • 21 лютого 2018 р. 16:32
            qmlRegisterType<ListModelPodsh>("SQLHelper", 1, 0, "ListModelPodsh");
            import SQLHelper 1.0
            QQmlApplicationEngine failed to load component
            qrc:/main.qml:341 Type CreatBO unavailable
            qrc:/CreatBO.qml:7 module "SQLHelper" is not installed
              Виталий Антипов
              • 21 лютого 2018 р. 16:34

              Ой, извиняюсь... надо же перед engine.load(QUrl(QLatin1String("qrc:/main.qml")));

                Виталий Антипов
                • 21 лютого 2018 р. 16:44

                Не работает

                void ListModelPodsh::updateModel()
                {
                    QObject* stack = this->parent()->findChild<QObject*>("stackView");
                    QString obRU=(stack->property("obRU")).toString();
                    QString obEN=(stack->property("obEN")).toString();
                    QSqlDatabase db = QSqlDatabase::database();
                    db.transaction();
                    // Обновление производится SQL-запросом к базе данных
                    this->setQuery("SELECT BasePodsh.id, BasePodsh.Oboznachenie, BasePodsh.OboznachenieEN, BasePodsh.dvnutr, BasePodsh.Dnaruzh, BasePodsh.B, "
                                   "BasePodsh.dtk, BasePodsh.ztk, BasePodsh.Ugol, BasePodsh.Massa, BasePodsh.Static, BasePodsh.Dinamic, BasePodsh.Name "
                                   "FROM BasePodsh WHERE BasePodsh.Oboznachenie LIKE '%"+obRU+"%' and BasePodsh.OboznachenieEN LIKE '%"+obEN+"%' "
                                   "ORDER BY BasePodsh.Oboznachenie");
                    while(this->canFetchMore()){
                        this->fetchMore();
                    }
                    qDebug()<<"this->canFetchMore()"<<this->canFetchMore();
                    db.commit();
                    if(!db.commit()){
                    db.rollback();
                    }
                }
                Не могу из StackView фильтры для запроса получить, ведь StackView еще не создан когда создана модель.
                  Evgenii Legotckoi
                  • 21 лютого 2018 р. 17:06

                  Ну про StackView вообще ничего сказано изначально не было...


                  Как вариант можете с помощью этой модели или изначальной формировать какой-нибудь массив с данными, который будет использоваться в качестве модели данных для ComboBox`a. И устанавливать каждую новую модель при запросе в комбобокс.
                    Виталий Антипов
                    • 21 лютого 2018 р. 17:19

                    Спасибо за ответы, есть над чем подумать

                      Виталий Антипов
                      • 23 лютого 2018 р. 08:14

                      По вашей предыдущей подсказке создал новый класс для получения модели данных, зарегистрировал его как тип данных QML и посредством Q_PROPERTY добавил свойство filter для фильтрации запроса.

                      modelpodsh.h
                      #ifndef MODELPODSH_H
                      #define MODELPODSH_H
                      
                      #include <QObject>
                      #include <QSqlQueryModel>
                      #include <QSqlQuery>
                      #include <QDebug>
                      
                      class ModelPodsh : public QSqlQueryModel
                      {
                          using BaseClass = QSqlQueryModel;
                      
                          Q_OBJECT
                          Q_PROPERTY(QString filter READ filter WRITE setFilter)
                      public:
                          enum Roles {
                              IdRole = Qt::UserRole + 1,
                              podsh_obRURole,
                              podsh_obENRole,
                              podsh_dvnRole,
                              podsh_dnarRole,
                              podsh_bRole,
                              podsh_dtkRole,
                              podsh_ztkRole,
                              podsh_aRole,
                              podsh_massaRole,
                              podsh_staticRole,
                              podsh_dinamicRole,
                              podsh_nameRole
                          };
                      
                          explicit ModelPodsh(QObject *parent = 0);
                          
                          QString filter(){return filter_;}
                          void setFilter(QString filter_in){filter_=filter_in;}
                      
                          QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
                      
                      protected:
                          QHash<int, QByteArray> roleNames() const;
                      
                      signals:
                      
                      public slots:
                          void updateModel();
                          int getId(int row);
                      public:
                          QString filter_;
                      };
                      #endif // MODELPODSH_H
                      modelpodsh.cpp
                      #include "modelpodsh.h"
                      
                      ModelPodsh::ModelPodsh(QObject *parent) :
                          BaseClass(parent)
                      {
                          this->updateModel();
                      }
                      
                      QVariant ModelPodsh::data(const QModelIndex & index, int role) const {
                          int columnId = role - Qt::UserRole - 1;
                          QModelIndex modelIndex = this->index(index.row(), columnId);
                          return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
                      }
                      
                      QHash<int, QByteArray> ModelPodsh::roleNames() const {
                          QHash<int, QByteArray> roles;
                          roles[IdRole] = "id";
                          roles[podsh_obRURole] = "podsh_obRU";
                          roles[podsh_obENRole] = "podsh_obEN";
                          roles[podsh_dvnRole] = "podsh_dvn";
                          roles[podsh_dnarRole] = "podsh_dnar";
                          roles[podsh_bRole] = "podsh_b";
                          roles[podsh_dtkRole] = "podsh_dtk";
                          roles[podsh_ztkRole] = "podsh_ztk";
                          roles[podsh_aRole] = "podsh_a";
                          roles[podsh_massaRole] = "podsh_massa";
                          roles[podsh_staticRole] = "podsh_static";
                          roles[podsh_dinamicRole] = "podsh_dinamic";
                          roles[podsh_nameRole] = "podsh_name";
                          return roles;
                      }
                      
                      void ModelPodsh::updateModel()
                      {
                          QSqlDatabase db = QSqlDatabase::database();
                          db.transaction();
                          // Обновление производится SQL-запросом к базе данных
                          this->setQuery("SELECT BasePodsh.id, BasePodsh.Oboznachenie, BasePodsh.OboznachenieEN, BasePodsh.dvnutr, BasePodsh.Dnaruzh, BasePodsh.B, "
                                         "BasePodsh.dtk, BasePodsh.ztk, BasePodsh.Ugol, BasePodsh.Massa, BasePodsh.Static, BasePodsh.Dinamic, BasePodsh.Name "
                                         "FROM BasePodsh WHERE BasePodsh.Oboznachenie LIKE '%"+filter_+"%' "
                                         "ORDER BY BasePodsh.Oboznachenie");
                          while(this->canFetchMore()){
                              this->fetchMore();
                          }
                          db.commit();
                          if(!db.commit()){
                          db.rollback();
                          }
                      }
                      
                      int ModelPodsh::getId(int row)
                      {
                          return this->data(this->index(row, 0), IdRole).toInt();
                      }
                      
                      .qml
                      ...
                      ComboBox {
                      ...
                      }
                      ModelPodsh {
                                 id: newmodel
                                 }
                      Button{
                      id: combo_obRU
                      ...
                      onClicked: {
                      newmodel.filter = combo_obRU.editText
                      combo_obRU.model = newmodel
                      newmodel.updateModel()
                      combo_obRU.popup.visible = true
                      }
                      }
                      Проблема решена. Но мне не нравится низкая скорость. Набрав в комбобоксе текст для фильтра и нажав кнопку, список комбобокса с данными открывается через 3-4 секунды. И еще... модель комбобоксу приходится присваивать только по нажатию кнопки фильтра. Тут проблема в том, что "Редактируемый комбинированный блок автоматически завершает свой текст на основе того, что доступно в модели". С предопределенной моделью текст в комбобоксе набирается крайне медленно (иногда при этом программа падает), поэтому в начале модель лучше не иметь вовсе.
                        Evgenii Legotckoi
                        • 23 лютого 2018 р. 08:42

                        Дайте подумать...

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

                        Я вот сейчас думаю на более свежую голову, а может быть мы с вами не в ту сторону пошли. Если Вам нужно просто найти значение из выборки, то может быть вам и не нужно каждый раз делать вызов запроса SQL. Ну была у вас одна модель... Сделали один фильтр при создании страницы с комбобоксами, и получили все значения сразу в каждом комбобоксе.

                        А вот этот самый editable должен просто включить возможность автозаполнения, то есть в существующей модели данных он будет искать нужное значение. То есть теоретически выполнить SQL-запрос нужно один раз. А потом, модель данных должна возвращать что-то, что отвечало бы за LIKE фильтр через метод data(), вот через него и должен искать ComboxBox нужную строку без изменения модели...

                        Вот сейчас я вас понял правильнее?
                          Виталий Антипов
                          • 23 лютого 2018 р. 08:50

                          Да. Но нужно найти не одно значение... Как пример: мне нужно найти подшипник 6306 2RS. Я просто вбиваю 306, комбобокс раскрывает свой список всех с 306 (6306, 6306 2RS, 6306 RS, 6306 2RSN и т.п.). Я выбираю нужный мне и дело в шляпе. По идее надо через proxymodel как-то работать, но для меня пока это сложно.

                            Виталий Антипов
                            • 23 лютого 2018 р. 08:58

                            Вот тут с gif наверное будет более понятно

                              Evgenii Legotckoi
                              • 25 лютого 2018 р. 05:02

                              Да, в принципе идея понятна.

                              Можно воспользоваться одной исходной моделью и делать по ней поиск. Найденные элементы добавлять в модель для отображения.
                              При этом исходная модель будет одна на все комбобоксы, а модель для отображения будет каждая для каждого комбобокса.
                              ListModel {
                                  id: sourceModel
                                  ListElement { text: "Banana" }
                                  ListElement { text: "Apple" }
                                  ListElement { text: "Coconut" }
                                  ListElement { text: "Aple" }
                                  ListElement { text: "Appppp" }
                              }
                              
                              ComboBox {
                                  id: comboBox
                                  editable: true
                              
                              
                                  model: ListModel {
                                      id: displayModel
                                  }
                              
                                  onAccepted: {
                                      displayModel.clear()
                                      for (var i = 0; i < sourceModel.count; ++i)
                                      {
                                          if (sourceModel.get(i).text.includes(editText))
                                              displayModel.append({text: sourceModel.get(i).text})
                                      }
                                  }
                              
                                  anchors.horizontalCenter: parent.horizontalCenter
                              }

                                Коментарі

                                Only authorized users can post comments.
                                Please, Log in or Sign up
                                AD

                                C++ - Тест 004. Указатели, Массивы и Циклы

                                • Результат:50бали,
                                • Рейтинг балів-4
                                m
                                • molni99
                                • 26 жовтня 2024 р. 01:37

                                C++ - Тест 004. Указатели, Массивы и Циклы

                                • Результат:80бали,
                                • Рейтинг балів4
                                m
                                • molni99
                                • 26 жовтня 2024 р. 01:29

                                C++ - Тест 004. Указатели, Массивы и Циклы

                                • Результат:20бали,
                                • Рейтинг балів-10
                                Останні коментарі
                                ИМ
                                Игорь Максимов22 листопада 2024 р. 11:51
                                Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                                Evgenii Legotckoi
                                Evgenii Legotckoi31 жовтня 2024 р. 14:37
                                Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                                A
                                ALO1ZE19 жовтня 2024 р. 08:19
                                Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                                ИМ
                                Игорь Максимов05 жовтня 2024 р. 07:51
                                Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                d
                                dblas505 липня 2024 р. 11:02
                                QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                Тепер обговоріть на форумі
                                Evgenii Legotckoi
                                Evgenii Legotckoi24 червня 2024 р. 15:11
                                добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                t
                                tonypeachey115 листопада 2024 р. 06:04
                                google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                                NSProject
                                NSProject04 червня 2022 р. 03:49
                                Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                                9
                                9Anonim25 жовтня 2024 р. 09:10
                                Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                                Слідкуйте за нами в соціальних мережах