М
МаркГлен26. Juni 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
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

21
IscanderChe
  • 26. Juni 2020 09:40

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

    М
    • 26. Juni 2020 10:07
    • (bearbeitet)

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

    // получаю данные
    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. Juni 2020 10:30
      • Die Antwort wurde als Lösung markiert.

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

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

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

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

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

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

          AC
          • 26. Juni 2020 10:45
          • (bearbeitet)

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

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

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

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

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

                М
                • 26. Juni 2020 11:41

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

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

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

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

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

                  AC
                  • 26. Juni 2020 11:43

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

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

                      IscanderChe
                      • 26. Juni 2020 11:49

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

                        М
                        • 26. Juni 2020 12:01

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

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

                        proxyTimeModel->setFilterKeyColumn(4);
                        
                          IscanderChe
                          • 26. Juni 2020 12:08

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

                            М
                            • 26. Juni 2020 12:11

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

                              AC
                              • 26. Juni 2020 12:18
                              • (bearbeitet)

                              По поводу вашего когда.
                              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. Juni 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. Juni 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. Juni 2020 05:03

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

                                      М
                                      • 27. Juni 2020 06:25
                                      • (bearbeitet)

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

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

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

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

                                        #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. Juni 2020 13:41

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

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

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

                                            Kommentare

                                            Nur autorisierte Benutzer können Kommentare posten.
                                            Bitte Anmelden oder Registrieren
                                            Letzte Kommentare
                                            A
                                            ALO1ZE19. Oktober 2024 08:19
                                            Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                                            ИМ
                                            Игорь Максимов5. Oktober 2024 07:51
                                            Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                            d
                                            dblas55. Juli 2024 11:02
                                            QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                            k
                                            kmssr8. Februar 2024 18:43
                                            Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                            Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                            Jetzt im Forum diskutieren
                                            J
                                            JacobFib17. Oktober 2024 03:27
                                            добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
                                            JW
                                            Jhon Wick1. Oktober 2024 15:52
                                            Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
                                            КГ
                                            Кирилл Гусарев27. September 2024 09:09
                                            Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
                                            F
                                            Fynjy22. Juli 2024 04:15
                                            при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

                                            Folgen Sie uns in sozialen Netzwerken