М
МаркГленJune 26, 2020, 9:27 a.m.

Сортировка и фильтрация в 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();
}

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

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!

21
IscanderChe
  • June 26, 2020, 9:40 a.m.

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

    М
    • June 26, 2020, 10:07 a.m.
    • (edited)

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

    // получаю данные
    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
      • June 26, 2020, 10:30 a.m.
      • The answer was marked as a solution.

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

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

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

        М
        • June 26, 2020, 10:35 a.m.

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

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

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

          AC
          • June 26, 2020, 10:45 a.m.
          • (edited)

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

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

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

            М
            • June 26, 2020, 10:49 a.m.

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

              М
              • June 26, 2020, 11:32 a.m.

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

                М
                • June 26, 2020, 11:41 a.m.

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

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

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

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

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

                  AC
                  • June 26, 2020, 11:43 a.m.

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

                    М
                    • June 26, 2020, 11:44 a.m.

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

                      IscanderChe
                      • June 26, 2020, 11:49 a.m.

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

                        М
                        • June 26, 2020, 12:01 p.m.

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

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

                        proxyTimeModel->setFilterKeyColumn(4);
                        
                          IscanderChe
                          • June 26, 2020, 12:08 p.m.

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

                            М
                            • June 26, 2020, 12:11 p.m.

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

                              AC
                              • June 26, 2020, 12:18 p.m.
                              • (edited)

                              По поводу вашего когда.
                              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
                                • June 26, 2020, 12:33 p.m.

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

                                Посмотрите в сторону кастомной модели от 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);
                                }
                                
                                  М
                                  • June 27, 2020, 4:48 a.m.

                                  Посмотрите в сторону кастомной модели от 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
                                    • June 27, 2020, 5:03 a.m.

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

                                      М
                                      • June 27, 2020, 6:25 a.m.
                                      • (edited)

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

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

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

                                        AC
                                        • June 27, 2020, 7:06 a.m.

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

                                        #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

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

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

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

                                          М
                                          • June 27, 2020, 1:41 p.m.

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

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

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

                                            Comments

                                            Only authorized users can post comments.
                                            Please, Log in or Sign up
                                            d
                                            • dsfs
                                            • April 26, 2024, 11:56 a.m.

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

                                            • Result:80points,
                                            • Rating points4
                                            d
                                            • dsfs
                                            • April 26, 2024, 11:45 a.m.

                                            C++ - Test 002. Constants

                                            • Result:50points,
                                            • Rating points-4
                                            d
                                            • dsfs
                                            • April 26, 2024, 11:35 a.m.

                                            C++ - Test 001. The first program and data types

                                            • Result:73points,
                                            • Rating points1
                                            Last comments
                                            k
                                            kmssrFeb. 9, 2024, 1:43 a.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, 5:30 p.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, 3:38 p.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. 19, 2023, 4:01 a.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
                                            PS
                                            Peter SonMay 4, 2024, 12:57 a.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, 9:07 p.m.
                                            Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
                                            IscanderChe
                                            IscanderCheApril 30, 2024, 11:22 a.m.
                                            Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
                                            G
                                            GarApril 22, 2024, 12:46 p.m.
                                            Clipboard Как скопировать окно целиком в clipb?
                                            Павел Дорофеев
                                            Павел ДорофеевApril 14, 2024, 9:35 a.m.
                                            QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь

                                            Follow us in social networks