2016-09-14 3 views
2

Wir haben eine QSortFilterProxyModel auf einem QTableView und zwei installiert (oder mehr) QLineEdit zum Filtern der Ansicht (basierend auf dem Text dieser QLineEdit s)ändern QSortFilterProxyModel Verhalten für mehrere Spaltenfilterung

Unserer Ansicht nach haben wir einen Schlitz Das sagt uns die Zeile von lineedits und die aktuelle Spalte, die wir wollen. Etwas wie dieses:

void onTextChange(int index, QString ntext) { 
    filter.setFilterKeyColumn(index); 
    filter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive)); 
} 

Auf der ersten Spalte haben wir Namen in der Sekunde, die wir Jahr des Geburtstages haben.

Jetzt geben wir ein Jahr für Spalte 2 ein (zum Beispiel 1985). Bis jetzt ist das Filtern in Ordnung, aber wenn wir zum ersten lineedit wechseln und einen Namen eingeben (zum Beispiel john), wird die vorherige Filterung basierend auf Jahr zurückgesetzt. Wie können wir dieses Verhalten für unsere benutzerdefinierte QSortFilterProxyModel ändern?

(Eigentlich, wenn wir die Filter KeyColumn die filtermodel Filter ändern müssen vorhandene Ansicht zurückgesetzt es nicht)

Update ...

Basierend auf @ Mike Antwort: Wenn Sie mit unbekannter Spaltenanzahl der Interaktion QMap<int, QRegExp> mit wird Ihnen helfen

+1

Sie können nur 2 Proxy-Modelle übereinander schichten. Eine für den Namen eine andere für das Jahr. und abhängig davon, welche Zeile Sie ändern, ändern Sie den entsprechenden Filter. – Hayt

Antwort

2

Sie können QSortFilterProxyModel Unterklasse, um es zwei separate Filter dauern (eine für den Namen und die andere für das Jahr), und überschreiben filterAcceptsRow, true nur dann zurückzugeben, wenn beide Filter erfüllt sind.

Die Qt-Dokumentation Custom Sort/Filter Model Example zeigt eine Unterklasse QSortFilterProxyModel, die Filter für Datumsangaben zusätzlich zum Hauptsaitenfilter, der für die Suche verwendet wird, verwenden kann.

Hier ist ein voll funktionsfähiges Beispiel dafür, wie ein subclassed QSortFilterProxyModel gelten zwei separate Filter für einen Tisch zu machen:

Example Screenshot

#include <QApplication> 
#include <QtWidgets> 

class NameYearFilterProxyModel : public QSortFilterProxyModel{ 
    Q_OBJECT 
public: 
    explicit NameYearFilterProxyModel(QObject* parent= nullptr): 
     QSortFilterProxyModel(parent){ 
     //general parameters for the custom model 
     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(); 
    } 
private: 
    QRegExp nameRegExp; 
    QRegExp yearRegExp; 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    //set up GUI 
    QWidget w; 
    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); 

    //fill with dummy data 
    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(); 
} 

#include "main.moc" 
0

Wenn Sie die 2 Eingänge mit einem "und" Filter verbinden möchten, können Sie sie einfach schichten.

So etwas sollte funktionieren.

QSortFilterProxyModel namefilter; 
nameFilter.setFilterKeyColumn(nameColum); 
QSortFilterProxyModel yearFilter; 
yearFilter.setFilterKeyColumn(yearColumn); 

yearFilter.setSourceModel(model); 
nameFilter.setSourceModel(&yearFilter); 
view.setSource(&nameFilter); 

//.... 


void onTextChange(int index, QString ntext) 
{ 
    switch(index) 
    { 
     case yearColumn: 
      yearFilter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive)); 
      break; 
     case nameColum: 
      namefilter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive)); 
      break;  
    } 
} 
1

Basierend auf @ Hayts Antwort und Kommentar. Da Sie zwei separate Filter in Ihrem Modell haben möchten, können Sie zwei verkettete haben QSortFilterProxyModel (man macht die Filterung basierend auf dem Namen, und die andere macht die Filterung basierend auf dem Jahr mit dem ersten Filtermodell als Quellmodell).

Hier ist ein voll funktionsfähiges Beispiel dafür, wie zwei separate Filter für einen Tisch haben:

Example Screenshot

#include <QApplication> 
#include <QtWidgets> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    //set up GUI 
    QWidget w; 
    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; 
    QSortFilterProxyModel yearFilterModel; 
    yearFilterModel.setSourceModel(&sourceModel); 
    QSortFilterProxyModel nameFilterModel; 
    //nameFilterModel uses yearFilterModel as source 
    nameFilterModel.setSourceModel(&yearFilterModel); 
    //tableView displayes the last model in the chain nameFilterModel 
    tableView.setModel(&nameFilterModel); 
    nameFilterModel.setFilterKeyColumn(0); 
    yearFilterModel.setFilterKeyColumn(1); 
    nameFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive); 
    yearFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive); 

    QObject::connect(&lineEditName, &QLineEdit::textChanged, &nameFilterModel, 
      static_cast<void (QSortFilterProxyModel::*)(const QString&)> 
      (&QSortFilterProxyModel::setFilterRegExp)); 
    QObject::connect(&lineEditYear, &QLineEdit::textChanged, &yearFilterModel, 
      static_cast<void (QSortFilterProxyModel::*)(const QString&)> 
      (&QSortFilterProxyModel::setFilterRegExp)); 

    //fill with dummy data 
    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(); 
} 
+0

@ Mike.Ist das ein universeller Weg? In vielen realen Situationen gibt es nicht nur 2 Spalten und Benutzer können auf verschiedene Spalten filtern.Wenn wir zum Beispiel eine zusätzliche Spalte (Höhe) zu Ihrem Beispiel hinzufügen wollen, sollte das Quellmodell der Ansicht sein? mit denen sollte Kind .... – IMAN4K

+0

Sie könnten Folgendes tun, um es kürzer und mehr auf den Punkt: 1. '#include ' 2. Halten Sie Layouts, Widgets, Modelle nach Wert, die Nutzung des Compilers Speicher für zu verwalten Sie - und es ist weniger Tipparbeit! 3. Lassen Sie die Klasse "Widget" fallen, das ist nicht notwendig. 4. Übergeben Sie das Widget an den Konstruktor des Layouts, um den Aufruf 'setLayout' zu speichern. 5. Ziehen Sie 'nullptr' über 'Q_NULLPTR' vor, da Sie sowieso C++ 11 verwenden; Letzteres ist nur für Pre-C++ 11-Code gedacht. –

+0

@ IMAN4K, können Sie sie in beliebiger Reihenfolge verketten, würde ich sagen (aus Gründen der Leistung), sie in der Reihenfolge verkettet zu haben, in der das erste Filtermodell der Filter ist, der die meisten Zeilen herausnimmt, dann etc ... – Mike

Verwandte Themen