М
МаркГлен26 червня 2020 р. 09: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 р. 09: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 р. 04: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 р. 05:03

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

                                      М
                                      • 27 червня 2020 р. 06:25
                                      • (відредаговано)

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

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

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

                                        AC
                                        • 27 червня 2020 р. 07: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

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

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

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

                                            Коментарі

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

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

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

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

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

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

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

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