Виталий Антипов
Виталий АнтиповАқп. 21, 2018, 9: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, 3: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, 4: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, 4:34 Т.Қ.

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

                Виталий Антипов
                • Ақп. 21, 2018, 4: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, 5:06 Т.Қ.

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


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

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

                      Виталий Антипов
                      • Ақп. 23, 2018, 8: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, 8:42 Т.Ж.

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

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

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

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

                        Вот сейчас я вас понял правильнее?
                          Виталий Антипов
                          • Ақп. 23, 2018, 8:50 Т.Ж.

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

                            Виталий Антипов
                            • Ақп. 23, 2018, 8:58 Т.Ж.

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

                              Evgenii Legotckoi
                              • Ақп. 25, 2018, 5: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
                              }

                                Пікірлер

                                Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                                Кіріңіз немесе Тіркеліңіз
                                Г

                                C++ - Тест 001. Первая программа и типы данных

                                • Нәтиже:66ұпай,
                                • Бағалау ұпайлары-1
                                t

                                C++ - Тест 001. Первая программа и типы данных

                                • Нәтиже:33ұпай,
                                • Бағалау ұпайлары-10
                                t

                                Qt - Тест 001. Сигналы и слоты

                                • Нәтиже:52ұпай,
                                • Бағалау ұпайлары-4
                                Соңғы пікірлер
                                G
                                GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
                                Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
                                d
                                dblas5Шілде 5, 2024, 11:02 Т.Ж.
                                QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                k
                                kmssrАқп. 8, 2024, 6:43 Т.Қ.
                                Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                АК
                                Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
                                Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                Енді форумда талқылаңыз
                                Evgenii Legotckoi
                                Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
                                добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                F
                                FynjyШілде 22, 2024, 4:15 Т.Ж.
                                при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
                                BlinCT
                                BlinCTМаусым 25, 2024, 1 Т.Ж.
                                Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
                                BlinCT
                                BlinCTМамыр 5, 2024, 5:46 Т.Ж.
                                Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
                                Evgenii Legotckoi
                                Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
                                Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

                                Бізді әлеуметтік желілерде бақылаңыз