Qt model/view understanding 01

There are two main ways to process data in Qt: 1) Directly operate the data item containing the data. This method is simple and easy to operate, but has the disadvantage of a single method, especially for big data or repeated in different locations. The data that appears must be operated on in sequence. If the actual mode changes, the data will need to be recoded during the program modification process, which consumes labor and resources. 2) Use the model/view model to string together data - model - view, and ensure the correct display of data and the diversity of display methods through the agreed interface. When the display needs to be readjusted, you only need to modify the view to ensure The interface remains unchanged, that is, data can be displayed in a new view.

1/2 Two ways to process data:

Views are bound to data:

View and data isolation:

Here, I mainly introduce the second model: model/view mode, taking QAbstractTableModel/QTableView as an example.

If it is in read-only mode, the model only needs to override the following three methods:

//a方法:返回模型行数。
int rowCount(const QModelIndex &parent) const; 

//b方法:返回模型列数。
int columnCount(const QModelIndex &parent) const; 

//c方法:返回index项的role角色的数据。其中index项中可以有多个角色,每个角色都可以有一个数据。
QVariant data(const QModelIndex &index, int role) const;

If the user wants to be able to edit data (edit mode), the model also needs to override the following two methods:

//d方法:设置模型中项的内容。
bool QAbstractItemModel::setData(const QModelIndex & index, 
                                 const QVariant & value, 
                                 int role= Qt::EditRole);

//e方法:返回项的编辑形式,默认情况下只有ItemIsSelectable和ItemIsEnabled,如果要可编辑,需要
//添加ItemIsEditable属性。
Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex & index) const

The a/b/c methods are pure virtual methods, and the inherited class must implement this method by the coder itself. The d/e method is a virtual function. The coder inherits this method and can directly call the base class method after implementing custom content.

Here we use the trackEditor example in "c++ gui programming with Qt4" to explain.

class MyTableModel : public QAbstractTableModel
{
public:
    explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);

    virtual int rowCount(const QModelIndex &parent) const;
    virtual int columnCount(const QModelIndex &parent) const;
    virtual QVariant data(const QModelIndex &index, int role) const;
    virtual QVariant headerData(int section,
                                Qt::Orientation orientation,
                                int role) const;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    virtual bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<Track>* pTracks;
};

Among them, "QList<Track>* tracks" is used to save the data collection displayed by the model. It is assigned when the model is initialized, and the data is displayed according to the algorithm of the data method.

MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{
    Q_UNUSED(parent);

    pTracks = tracks;
}

The constructor assigns values ​​to tracks.

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return pTracks->count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return 2;
}

The above two methods return the number of rows/columns of the model. Because the amount of data in tracks is uncertain, their count method is directly returned to ensure the latest value every time;

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if ( !index.isValid()) {
        return QVariant();
    }

    if (Qt::DisplayRole == role || Qt::EditRole == role) {
        if (0 == index.column()) {
            return pTracks->at(index.row()).getTitle();
        } else if (1 == index.column()) {
            return pTracks->at(index.row()).getDuration();
        }
    }

    return QVariant();
}

Depending on the data type and column, different data information is returned. When the index does not fall into the above two situations, a QVariant object is returned. EditRole ensures that when the user edits data, the data appears in selected mode instead of disappearing directly.

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if ( !index.isValid()) {
        return false;
    }

    if (Qt::EditRole == role) {
        (*pTracks)[index.row()].setTitle(value.toString());
        emit dataChanged(index, index);

        return true;
    } else {
        return QAbstractTableModel::setData(index, value, role);
    }
}

According to the coder processing and incoming role, set the value of the index item and the corresponding data in the tracks and update the index data display. When the incoming data coder does not process it, it directly calls the base class method to process it. It does not specify which column to edit because the editable columns are set later through the flags method, so there is no need to specify it here . Please note here that the setData method determines the Qt::EditRole role, and the data method is Qt::DisplayRole, but what is saved and read are tracks. This is what the coder should pay attention to. In different processes, the program The roles they occupy are different, but they all operate the same database (tracks). This should be noted.

Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{
    if (0 == index.column()) {
        return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
    } else {
        return QAbstractTableModel::flags(index);
    }
}

The processing flag of each item in the model defaults to (ItemIsEnabled | ItemIsSelectable), and the coder can set items with different attributes as required. Here, set the 0th column to be editable and the remaining columns to be uneditable.

The program running results show the same data using TableView and ListView respectively:

The specific code is as follows: There are three classes: maindialg, mytablemodel, tack, and a main running class. The specific interface file is the ui generated by Qt itself.

track.h

#ifndef TRACK_H
#define TRACK_H

#include <QString>

class Track
{
public:
    explicit Track(const QString& title = "", int duration = 0);

    QString getTitle() const;
    int getDuration() const;

    void setDuration(int duration);
    void setTitle(QString title);

private:
    QString mTitle;
    int mDuration;
};

#endif // TRACK_H

track.cpp

#include "track.h"

Track::Track(const QString &title, int duration) :
    mTitle(title),
    mDuration(duration)
{

}

QString Track::getTitle() const
{
    return mTitle;
}

int Track::getDuration() const
{
    return mDuration;
}

void Track::setDuration(int duration)
{
    mDuration = duration;
}

void Track::setTitle(QString title)
{
    mTitle = title;
}

mytablemodel.h

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H

#include <QWidget>
#include <QAbstractTableModel>
#include "track.h"

class MyTableModel : public QAbstractTableModel
{
public:
    explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);

    virtual int rowCount(const QModelIndex &parent) const;
    virtual int columnCount(const QModelIndex &parent) const;
    virtual QVariant data(const QModelIndex &index, int role) const;
    virtual QVariant headerData(int section,
                                Qt::Orientation orientation,
                                int role) const;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    virtual bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<Track>* pTracks;
};

#endif // MYTABLEMODEL_H

mytablemodel.cpp

#include "mytablemodel.h"

MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{
    Q_UNUSED(parent);

    pTracks = tracks;
}

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return pTracks->count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return 2;
}

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if ( !index.isValid()) {
        return QVariant();
    }

    if (Qt::DisplayRole == role) {
        if (0 == index.column()) {
            return pTracks->at(index.row()).getTitle();
        } else if (1 == index.column()) {
            return pTracks->at(index.row()).getDuration();
        }
    }

    return QVariant();
}

QVariant MyTableModel::headerData(int section,
                                  Qt::Orientation orientation,
                                  int role) const
{
    /*if (Qt::Vertical == orientation) {
        return QVariant();
    }*/

    if (Qt::DisplayRole == role && Qt::Horizontal == orientation) {
        switch (section) {
        case 0:
            return "first";

        case 1:
            return "second";
        }
    }

    return QVariant();
}

Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{
    if (0 == index.column()) {
        return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
    } else {
        return QAbstractTableModel::flags(index);
    }
}

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if ( !index.isValid()) {
        return false;
    }

    if (Qt::EditRole == role) {
        (*pTracks)[index.row()].setTitle(value.toString());
        emit dataChanged(index, index);

        return true;
    } else {
        return QAbstractTableModel::setData(index, value, role);
    }
}

maindialog.h

#ifndef MAINDIALOG_H
#define MAINDIALOG_H

#include <QDialog>
#include <QTableView>
#include <QListView>
#include "mytablemodel.h"

namespace Ui {
class MainDialog;
}

class MainDialog : public QDialog
{
    Q_OBJECT

public:
    explicit MainDialog(QWidget *parent = 0);
    ~MainDialog();

    void setTableModel(MyTableModel* model);

    void setListModel(MyTableModel* model);

private:
    Ui::MainDialog *ui;

    QTableView* pTableView;
    QListView* pListView;
};

#endif // MAINDIALOG_H

maindialog.cpp

#include<QGridLayout>
#include "maindialog.h"
#include "ui_maindialog.h"

MainDialog::MainDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::MainDialog),
    pTableView(new QTableView(this)),
    pListView(new QListView(this))
{
    ui->setupUi(this);

    QVBoxLayout* layout(new QVBoxLayout(this));
    layout->addWidget(pTableView);
    layout->addWidget(pListView);
    setLayout(layout);

    setAttribute(Qt::WA_DeleteOnClose);
}

MainDialog::~MainDialog()
{
    delete ui;
}

void MainDialog::setTableModel(MyTableModel *model)
{
    pTableView->setModel(model);
}

void MainDialog::setListModel(MyTableModel* model)
{
    pListView->setModel(model);
}

main.cpp

#include <QApplication>
#include "maindialog.h"
#include "track.h"
#include "mytablemodel.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QList<Track> tracks;
        tracks << Track("The Flying Dutchman: Overture", 630)
               << Track("The Flying Dutchman: Wie aus der Fern laengst "
                        "vergangner Zeiten", 374)
               << Track("The Flying Dutchman: Steuermann, lass die Wacht",
                        152)
               << Track("Die Walkuere: Ride of the Valkyries", 286)
               << Track("Tannhaeuser: Freudig begruessen wir die edle "
                        "Halle", 384)
               << Track("Tannhaeuser: Wie Todesahnung - O du mein holder "
                        "Abendstern", 257)
               << Track("Lohengrin: Treulich gefuert ziehet dahnin", 294)
               << Track("Lohengrin: In fernem Land", 383)
               << Track("Die Meistersinger von Nuernberg: Overture", 543)
               << Track("Die Meistersinger von Nuernberg: Verachtet mir "
                        "die Meister nicht", 200)
               << Track("Die Meistersinger von Nuernberg: Ehrt eure "
                        "deutschen Meister", 112)
               << Track("Goetterdaemmerung: Funeral Music", 469)
               << Track("Tristan und Isolde: Mild und leise, wie er "
                        "laechelt", 375);

    MyTableModel model(&tracks);

    MainDialog* w(new MainDialog(0));
    w->setTableModel(&model);
    w->setListModel(&model);
    w->show();

    return a.exec();
}

Guess you like

Origin blog.csdn.net/weiweiqiao/article/details/133562285