Using QTableView with a model
Asked Answered
A

1

12

I have the QVector cars that I want to filter basing on the car's registration number. I want to create a new filtered vector. I don't think that this is ok because i'm iterating 2 vectors, copying from the first one to the second one. Am I doing this right?

void MainWindow::on_actionBy_registration_number_triggered()
{
    myDialog = new MyDialog(this);
    myDialog->exec();

    QString toSearchString = myDialog->getRegistrationNumber();
    QVector<Vehicle> founded;
    QVectorIterator<Vehicle> iterator(cars);
    while(iterator.hasNext()){
        Vehicle car = iterator.next();
        QString num = car.getRegistration().getRegistrationNumber();
        if(num.contains(toSearchString,Qt::CaseInsensitive)){
            founded.append(car);
        }
    }
    model = new QStandardItemModel(founded.size(),5,this);

    //create header
    createHeader(model);

    int j = 0; //row
    QVectorIterator<Vehicle> iter(founded);
    while(iter.hasNext()){
        Vehicle output = iter.next();
        //set car
        QString makeAndModel = output.getGeneralData().getMake() + output.getGeneralData().getModel();
        QStandardItem *mAndM = new QStandardItem(QString(makeAndModel));
        model->setItem(j,0,mAndM);

        //set type
        QStandardItem *type = new QStandardItem(QString(output.getGeneralData().getType()));
        model->setItem(j,1,type);

        //set mileage
        QString mileageString = QString::number(output.getGeneralData().getMileage());
        QStandardItem *mileage = new QStandardItem(QString(mileageString));
        model->setItem(j,2,mileage);

        //set year
        QString yearString = QString::number(output.getGeneralData().getYear());
        QStandardItem *year = new QStandardItem(QString(yearString));
        model->setItem(j,3,year);


        //set registration
        QString regString = VehicleHelper::convertBoolToString(output.getRegistration().isRegistered());
        QStandardItem *regDate = new QStandardItem(QString(regString));
        model->setItem(j,4,regDate);
        j++;
    }

    ui->tableView->setModel(model);
    ui->tableView->setEnabled(false);
}
Altitude answered 23/9, 2013 at 16:31 Comment(1)
I think that you should not do premature optimization. If you Vehice class implements COW behaviour then all OK. Only proposal - you may use QList class instead of QVector. It's more prefferable in your case, because it keeps pointers on data type instead of explicit values.Entero
D
21

This can be done neatly using a proxy filter model. Below is a self-contained example that runs on both Qt 4 and 5.

screenshot

// https://github.com/KubaO/stackoverflown/tree/master/questions/filter-18964377
#include <QtGui>
#if QT_VERSION_MAJOR > 4
#include <QtWidgets>
#endif

class Vehicle {
   QString m_make, m_model, m_registrationNumber;
public:
   Vehicle(const QString & make, const QString & model, const QString & registrationNumber) :
      m_make{make}, m_model{model}, m_registrationNumber{registrationNumber} {}
   QString make() const { return m_make; }
   QString model() const { return m_model; }
   QString registrationNumber() const { return m_registrationNumber; }
   bool isRegistered() const { return !m_registrationNumber.isEmpty(); }
};

class VehicleModel : public QAbstractTableModel {
   QList<Vehicle> m_data;
public:
   VehicleModel(QObject * parent = {}) : QAbstractTableModel{parent} {}
   int rowCount(const QModelIndex &) const override { return m_data.count(); }
   int columnCount(const QModelIndex &) const override { return 3; }
   QVariant data(const QModelIndex &index, int role) const override {
      if (role != Qt::DisplayRole && role != Qt::EditRole) return {};
      const auto & vehicle = m_data[index.row()];
      switch (index.column()) {
      case 0: return vehicle.make();
      case 1: return vehicle.model();
      case 2: return vehicle.registrationNumber();
      default: return {};
      };
   }
   QVariant headerData(int section, Qt::Orientation orientation, int role) const override {
      if (orientation != Qt::Horizontal || role != Qt::DisplayRole) return {};
      switch (section) {
      case 0: return "Make";
      case 1: return "Model";
      case 2: return "Reg.#";
      default: return {};
      }
   }
   void append(const Vehicle & vehicle) {
      beginInsertRows({}, m_data.count(), m_data.count());
      m_data.append(vehicle);
      endInsertRows();
   }
};

class Widget : public QWidget {
   QGridLayout m_layout{this};
   QTableView m_view;
   QPushButton m_button{"Filter"};
   VehicleModel m_model;
   QSortFilterProxyModel m_proxy;
   QInputDialog m_dialog;
public:
   Widget() {
      m_layout.addWidget(&m_view, 0, 0, 1, 1);
      m_layout.addWidget(&m_button, 1, 0, 1, 1);
      connect(&m_button, SIGNAL(clicked()), &m_dialog, SLOT(open()));
      m_model.append({"Volvo", "240", "SQL8941"});
      m_model.append({"Volvo", "850", {}});
      m_model.append({"Volvo", "940", "QRZ1321"});
      m_model.append({"Volvo", "960", "QRZ1628"});
      m_proxy.setSourceModel(&m_model);
      m_proxy.setFilterKeyColumn(2);
      m_view.setModel(&m_proxy);
      m_dialog.setLabelText("Enter registration number fragment to filter on. Leave empty to clear filter.");
      m_dialog.setInputMode(QInputDialog::TextInput);
      connect(&m_dialog, SIGNAL(textValueSelected(QString)),
              &m_proxy, SLOT(setFilterFixedString(QString)));
   }
};

int main(int argc, char *argv[])
{
   QApplication a{argc, argv};
   Widget w;
   w.show();
   return a.exec();
}
Danit answered 23/9, 2013 at 17:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.