М
МаркГлен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
                                            AD

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

                                            • Result:50points,
                                            • Rating points-4
                                            m

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

                                            • Result:80points,
                                            • Rating points4
                                            m

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

                                            • Result:20points,
                                            • Rating points-10
                                            Last comments
                                            i
                                            innorwallNov. 14, 2024, 12:07 p.m.
                                            Circuit switching and packet data transmission networks Angioedema 1 priligy dapoxetine
                                            i
                                            innorwallNov. 14, 2024, 11:42 a.m.
                                            How to Copy Files in Linux If only females relatives with DZ offspring were considered these percentages were 23 order priligy online uk
                                            i
                                            innorwallNov. 14, 2024, 9:09 a.m.
                                            Qt/C++ - Tutorial 068. Hello World using the CMAKE build system in CLion ditropan pristiq dosing With the Yankees leading, 4 3, Rivera jogged in from the bullpen to a standing ovation as he prepared for his final appearance in Chicago buy priligy pakistan
                                            i
                                            innorwallNov. 14, 2024, 4:05 a.m.
                                            EVILEG-CORE. Using Google reCAPTCHA 2001; 98 29 34 priligy buy
                                            i
                                            innorwallNov. 14, 2024, 4 a.m.
                                            PyQt5 - Lesson 007. Works with QML QtQuick (Signals and slots) priligy 30mg Am J Obstet Gynecol 171 1488 505
                                            Now discuss on the forum
                                            i
                                            innorwallNov. 14, 2024, 3:39 a.m.
                                            добавить qlineseries в функции priligy amazon canada 93 GREB1 protein GREB1 AB011147 6
                                            i
                                            innorwallNov. 11, 2024, 10:55 a.m.
                                            Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
                                            9
                                            9AnonimOct. 25, 2024, 9:10 a.m.
                                            Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                                            Follow us in social networks