М
МаркГлен26 июня 2020 г. 9:27

Сортировка и фильтрация в QTableView, связь с моделью через Custom QSortFilterProxyModel

QTableView, QSortFilterProxyModel

Имеется QSqlQueryModel, делаю proxyModel->setSourceModel(model) и view->setModel(proxyModel).

view->setSortingEnabled(true) работает отлично, но пытаюсь по клику на строчку получить данные и понимаю что сортируется только view, а в модели сортировка не меняется.

То есть если была таблица с данными по возрастанию row1, row2, row3; я отсортировал row3, row2, row1 - по клику на row3 получаю доступ к row1.

Если у кого-то есть понимание поделитесь пожалуйста.

upd: помогли подсказки и поддержка пользователей и этот найденный пример.

custom_sort_filter_proxy_model.h

#include <QApplication>
#include <QtWidgets>

class NameYearFilterProxyModel : public QSortFilterProxyModel{
    Q_OBJECT
    QRegExp nameRegExp;
    QRegExp yearRegExp;
public:
    explicit NameYearFilterProxyModel(QObject* parent= nullptr):
        QSortFilterProxyModel(parent)
    {
        nameRegExp.setCaseSensitivity(Qt::CaseInsensitive);
        yearRegExp.setCaseSensitivity(Qt::CaseInsensitive);
        yearRegExp.setPatternSyntax(QRegExp::RegExp);
        nameRegExp.setPatternSyntax(QRegExp::RegExp);
    }

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const  override{
        QModelIndex nameIndex= sourceModel()->index(sourceRow, 0, sourceParent);
        QModelIndex yearIndex= sourceModel()->index(sourceRow, 1, sourceParent);

        QString name= sourceModel()->data(nameIndex).toString();
        QString year= sourceModel()->data(yearIndex).toString();

        return (

            name.contains(nameRegExp) && year.contains(yearRegExp)

            );
    }
public slots:
    void setNameFilter(const QString& regExp){
        nameRegExp.setPattern(regExp);
        invalidateFilter();
    }
    void setYearFilter(const QString& regExp){
        yearRegExp.setPattern(regExp);
        invalidateFilter();
    }
};

custom_sort_filter_proxy_model.cpp

#include "custom_sort_filter_proxy_model.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //set up GUI
    QWidget w;
    w.setWindowTitle("Custom SortFilterProxyModel");

    QVBoxLayout layout(&w);
    QHBoxLayout hLayout;
    QLineEdit lineEditName;
    QLineEdit lineEditYear;

    lineEditName.setPlaceholderText("name filter");
    lineEditYear.setPlaceholderText("year filter");
    lineEditYear.setValidator(new QRegExpValidator(QRegExp("[0-9]*")));
    lineEditYear.setMaxLength(4);
    hLayout.addWidget(&lineEditName);
    hLayout.addWidget(&lineEditYear);

    QTableView tableView;
    layout.addLayout(&hLayout);
    layout.addWidget(&tableView);

    //set up models
    QStandardItemModel sourceModel;
    NameYearFilterProxyModel filterModel;;
    filterModel.setSourceModel(&sourceModel);
    tableView.setModel(&filterModel);

    QObject::connect(&lineEditName, &QLineEdit::textChanged,
                     &filterModel, &NameYearFilterProxyModel::setNameFilter);
    QObject::connect(&lineEditYear, &QLineEdit::textChanged,
                     &filterModel, &NameYearFilterProxyModel::setYearFilter);


    QVector<QString> names{"Danny", "Christine", "Lars",
                           "Roberto", "Maria"};
    for(int i=0; i<100; i++){
        QList<QStandardItem*> row;
        row.append(new QStandardItem(names[i%names.size()]));
        row.append(new QStandardItem(QString::number((i%9)+1980)));
        sourceModel.appendRow(row);
    }
    w.show();
    return a.exec();
}

Так же решение со сбитой нумерацией строк в комментариях.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

21
IscanderChe
  • 26 июня 2020 г. 9:40

А как получаете данные? Код приведите.

    М
    • 26 июня 2020 г. 10:07
    • (ред.)

    Возможно даже лишнего немного оставил, в целом картина такая:

    // получаю данные
    QSqlQuery query;
    QString str;
            str=("SELECT bla-bla-bla FROM bla "
                 "LEFT JOIN  bla "
                 "ON bla-bla-bla.. ");
            query.exec(str);
    
    model = new QSqlQueryModel;
    model->setQuery(query);
    
    // для фильтрации по колонкам
    proxyOneModel->setSourceModel(model);
    proxyTwoModel->setSourceModel(proxyOneModel);
    proxyThreeModel->setSourceModel(proxyTwoModel);
    proxyFourModel->setSourceModel(proxyThreeModel);
    proxyFiveModel->setSourceModel(proxyFourModel);
    
    view->setModel(proxyFiveModel);
    
    // Включаю сортировку
    view->setSortingEnabled(true);
    
    

    По клику на одну из колонок

    void dataBrowser::onTableClicked(const QModelIndex &index)
    {
        if (index.isValid()) {
            int columnNumber = index.column();
            int rowNumber = index.row();
    
            if (columnNumber==2)
            {
                QModelIndex i = model->index(rowNumber, 0); // The first column data.
                emit setIdFromMain(i.data().toInt()); // по id записи вытаскиваю запросом строчку 
                //в другое место, то есть тут получаю не id строчки которую вижу в таблице 
                //а id который соответствует первоначальной сортировке по умолчанию
            }
        }
    }
    
     connect(view, SIGNAL(clicked(const QModelIndex &)), this, SLOT(onTableClicked(const QModelIndex &)));
    

    Я прошу прощения если от кода глаза слезятся, я учусь.

      AC
      • 26 июня 2020 г. 10:30
      • Ответ был помечен как решение.

      Без кода сложно сказать.
      Лучше всего создать к примеру свои классы

      BaseSqlQueryModel *model        = new BaseSqlQueryModel(strQuery, ui->tableView); // класс для обработки вывода данных
      BaseSortFilterProxyModel *proxy = new BaseSortFilterProxyModel(this);             // класс для сортировки
      model->setQuery(getStrQuery());
      proxy->setSourceModel(model);
      ui->tableView->setModel(proxy);
      

      В этих классах переопределить виртуальные методы ... взависимости от кода и проекта.

        М
        • 26 июня 2020 г. 10:35

        код я тут привёл https://evileg.com/en/forum/topic/1421/#post-8028

        Страшно даже думать об этом, но если нет стандартных решений то придётся учиться.

        Спасибо за ответ!

          AC
          • 26 июня 2020 г. 10:45
          • (ред.)

          Выложети весь код.
          Не понятно proxyOneModel ...
          С вашего кода я понимаю (годаю) что proxyOneModel унаследован от QSqlQueryModel
          Вы должны использовать класс QSortFilterProxyModel

          QSqlQueryModel *model        = new QSqlQueryModel;
          QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
          proxy->setSourceModel(model);
          ui->tableView->setModel(proxy);
          

          Сортировка должна происходить в proxy , получать данные из model

            М
            • 26 июня 2020 г. 10:49

            Пытался адаптировать, чтобы не вникать в подробности, типа правила хорошего тона. Позже выложу по максимуму тогда. p.s., да, proxy это QSortFilterProxyModel

              М
              • 26 июня 2020 г. 11:32

              весь код как есть добавил в тело поста

                М
                • 26 июня 2020 г. 11:41

                Так. Убрал позорятину свою и без неё теперь видно. Заметил ошибку

                тут model заменил на proxy:

                QModelIndex i = model->index(rowNumber, 0); // The first column data.
                

                всё заработало как надо!

                спасибо всем кто отреагировал!!!

                  AC
                  • 26 июня 2020 г. 11:43

                  Да, не успел указать.

                    М
                    • 26 июня 2020 г. 11:44

                    Спасибо! :) Фух, достала эта ошибка.

                      IscanderChe
                      • 26 июня 2020 г. 11:49

                      А что по решаемой задаче должно получаться? У меня такое чувство, что вы лишних моделей QSortFilterProxy понасоздавали и всё можно было в одну модель засунуть.

                        М
                        • 26 июня 2020 г. 12:01

                        Может быть и лишние, но не понял как по-другому. Каждая модель для отдельного фильтра

                        ведь можно установить только один FilterKeyColumn для модели:

                        proxyTimeModel->setFilterKeyColumn(4);
                        
                          IscanderChe
                          • 26 июня 2020 г. 12:08

                          Посмотрите в сторону кастомной модели от QSortFilterProxyModel. В примерах Qt есть, Custom Sort/Filter Model Example. Так можно реализовать фильтрацию по нескольким полям, как вам и надо.

                            М
                            • 26 июня 2020 г. 12:11

                            Попробую и тогда отпишусь по результату.

                              AC
                              • 26 июня 2020 г. 12:18
                              • (ред.)

                              По поводу вашего когда.
                              1 - Согласен с МаркГлен ​...

                              Посмотрите в сторону кастомной модели от QSortFilterProxyModel. В примерах Qt есть, Custom Sort/Filter Model Example. Так можно реализовать фильтрацию по нескольким полям, как вам и надо.

                              2 - Когда вы определяете/устанавливаете ширину колонок лучше использовать локальные константы (код лучше читается).
                              Пример:

                              #include "mainwindow.h"
                              #include "ui_mainwindow.h"
                              
                              static const int COLUMN_ID = 0;   // ------- !!!!!!!!!!!!!!!!!
                              static const int COLUMN_NAME = 1; // ------- !!!!!!!!!!!!!!!!!
                              
                              MainWindow::MainWindow(QWidget *parent)
                                  : QMainWindow(parent)
                                  , ui(new Ui::MainWindow)
                              {
                              
                              }
                              

                              3 - По поводу connect используете старый синтаксис.

                              connect(viewWindow, SIGNAL(triggered()), this, SLOT(show()));     // старый синтаксис
                              connect(viewWindow, &QAction::triggered, this, &NameClass::show); // новый синтаксис
                              
                                AC
                                • 26 июня 2020 г. 12:33

                                Забегая наперед - у вас возникла ещё одна проблема с сортировкой нумерации строк.
                                Как уже было сказано ...

                                Посмотрите в сторону кастомной модели от QSortFilterProxyModel

                                Необходимо переопределить виртуальный метод ...

                                QVariant BaseSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
                                {
                                    // переопределение сортировки нумерации строк
                                    if (role == Qt::DisplayRole){
                                        if (orientation == Qt::Vertical || section == 0){
                                            return section + 1;
                                        }
                                    }
                                    return QSortFilterProxyModel::headerData(section, orientation, role);
                                }
                                
                                  М
                                  • 27 июня 2020 г. 4:48

                                  Посмотрите в сторону кастомной модели от QSortFilterProxyModel

                                  Сложновато для меня, не понимаю что надо делать и что происходит. Наверное мне ещё рано.

                                  Собезъянничал вот так:

                                  basesortfilterproxymodel.h

                                  #include <QSortFilterProxyModel>
                                  #include <QVariant>
                                  
                                  class BaseSortFilterProxyModel : public QSortFilterProxyModel
                                  {
                                  public:
                                      BaseSortFilterProxyModel(QObject *parent = nullptr);
                                      QVariant headerData(int section, Qt::Orientation orientation, int role);
                                  };
                                  

                                  basesortfilterproxymodel.cpp

                                  #include "basesortfilterproxymodel.h"
                                  
                                  
                                  BaseSortFilterProxyModel::BaseSortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
                                  {
                                  
                                  }
                                  
                                  QVariant BaseSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role)
                                  {
                                      // переопределение сортировки нумерации строк
                                      if (role == Qt::DisplayRole){
                                          if (orientation == Qt::Vertical || section == 0){
                                              return section + 1;
                                          }
                                      }
                                      return BaseSortFilterProxyModel::headerData(section, orientation, role);
                                  }
                                  
                                  

                                  Заменил везде QSortFilterProxyModel на BaseSortFilterProxyModel, ничего не меняется. Наверное если сходу не понятно, то бесполезно и пытаться разобраться? Или есть какие-то доки и мануалы которые можно почитать.

                                    IscanderChe
                                    • 27 июня 2020 г. 5:03

                                    Пример смотрели? Там всё более-менее понятно.

                                      М
                                      • 27 июня 2020 г. 6:25
                                      • (ред.)

                                      Пример смотрели? Там всё более-менее понятно.

                                      Ну с сортировкой вертикальных заголовков разобрался теперь :)

                                      Фильтры смотрю.

                                        AC
                                        • 27 июня 2020 г. 7:06

                                        Доброго времени суток.
                                        Вы начали правильно, но должны продолжить и дочитать документацию до конца.

                                        #ifndef BASESORTFILTERPROXYMODEL_H
                                        #define BASESORTFILTERPROXYMODEL_H
                                        
                                        #include <QObject>
                                        #include <QDebug>
                                        #include <QDate>
                                        #include <QDateTime>
                                        #include <QSortFilterProxyModel>
                                        
                                        class BaseSortFilterProxyModel : public QSortFilterProxyModel
                                        {
                                            Q_OBJECT
                                        public:
                                            BaseSortFilterProxyModel(QObject *parent = nullptr);
                                        
                                            virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
                                        
                                        protected:
                                            bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
                                        };
                                        
                                        #endif // BASESORTFILTERPROXYMODEL_H
                                        

                                        Вам нужно разобраться с методом bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
                                        Лучше всего создать проект-пример в котором запустить отладку проекта и разобраться.
                                        1. Документация
                                        2. Путь к примеру из самого QT Creator (у меня linux) - Qt/Examples/Qt-5.14.2/widgets/itemviews/customsortfiltermodel

                                        Не сдавайтесь и будьте упрямее ...

                                        Сложновато для меня, не понимаю что надо делать и что происходит. Наверное мне ещё рано.

                                        ... перечитайте ещё раз, если не поймёте запустите отладку проекта-примера и разберитесь в простом примере, а уж потом подумайте как применить к вашему проекту.

                                          М
                                          • 27 июня 2020 г. 13:41

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

                                          Сделал изменения в теле топика.

                                          Теперь ещё надо все миллион сигналов переписать по-новому.

                                            Комментарии

                                            Только авторизованные пользователи могут публиковать комментарии.
                                            Пожалуйста, авторизуйтесь или зарегистрируйтесь
                                            e
                                            • ehot
                                            • 1 апреля 2024 г. 0:29

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

                                            • Результат:78баллов,
                                            • Очки рейтинга2
                                            B

                                            C++ - Тест 002. Константы

                                            • Результат:16баллов,
                                            • Очки рейтинга-10
                                            B

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

                                            • Результат:46баллов,
                                            • Очки рейтинга-6
                                            Последние комментарии
                                            k
                                            kmssr9 февраля 2024 г. 5:43
                                            Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                            АК
                                            Анатолий Кононенко5 февраля 2024 г. 12:50
                                            Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                            EVA
                                            EVA25 декабря 2023 г. 21:30
                                            Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                            J
                                            JonnyJo25 декабря 2023 г. 19:38
                                            Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                            G
                                            Gvozdik19 декабря 2023 г. 8:01
                                            Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                            Сейчас обсуждают на форуме
                                            a
                                            a_vlasov14 апреля 2024 г. 16:41
                                            Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                                            Павел Дорофеев
                                            Павел Дорофеев14 апреля 2024 г. 12:35
                                            QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                                            f
                                            fastrex4 апреля 2024 г. 14:47
                                            Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
                                            P
                                            Pisych27 февраля 2023 г. 15:04
                                            Как получить в массив значения из связанной модели? Спасибо, разобрался:))
                                            AC
                                            Alexandru Codreanu19 января 2024 г. 22:57
                                            QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

                                            Следите за нами в социальных сетях