Qt model/view理解1--修改20151125

在Qt中對數據處理主要有兩種方式:1)直接對包含數據的的數據項item進行操做,這種方法簡單、易操做,現實方式單一的缺點,特別是對於大數據或在不一樣位置重複出現的數據必須依次對其進行操做,若是現實方式改變,則在改動程序過程當中還需對數據進行從新編碼操做,費工費資源。2)採用model/view模型,將數據--模型--視圖三者串起來,經過約定的接口保證數據的正確顯示和顯示方式的多樣性,當須要從新調整顯示時,只需修改視圖,保證接口不變,便可以新view顯示數據。c++

1/2兩種處理數據方式:web

在此,我主要介紹model/view模式,在此以QAbstractTableModel/QTableView爲例。算法

若是是隻讀模式,model只要重寫如下三個方法:數據庫

//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;

若是用戶要可以編輯數據(編輯模式),model還須要重寫如下兩個方法:ide

//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

其中a/b/c方法爲純虛函數(pure virtual method),繼承的類必須由coder本身實現此方法。d/e方法爲虛函數(virtual),coder在繼承了此方法,實現自定義內容後可直接調用基類方法。函數

在此咱們以《c++ gui programming with Qt4》中的trackEditor例子做一講解。大數據

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;
};

其中「QList<Track>* tracks」是用來保存model所顯示的數據集合,在model初始化時被賦值,根據data方法的算法調用其中數據顯示。ui

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

    pTracks = tracks;
}

構造函數對tracks進行賦值。
this

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;
}

以上2個方法返回model的行/列數,由於tracks中的數據量不肯定,因此直接返回其count方法,保證每次都是最新值;編碼

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();
}

根據數據類型和所在列,返回不一樣的數據信息,當index都不屬於以上兩種狀況時,返回QVariant對象。EditRole保證了當用戶編輯數據時,數據顯示的是被選中模式而不是直接消失。

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);
    }
}

根據coder處理和傳入角色,設置index處項的值及tracks中對應處的數據並更新index的數據顯示。當傳入數據coder不處理時,則直接調用基類方法處理,再辭沒有特別指明第幾列進行編輯,由於是後面經過flags方法來設定了可編輯的列,故此處不用再特別指明。在此請注意,setData方法是判斷的是Qt::EditRole角色,data方法是Qt::DisplayRole,可是保存、讀取的都是tracks,這正是coder要注意的,在不一樣的過程時,程序所處於的角色不一樣,可是都操做一樣的數據庫(tracks),這點要注意。

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

model中每一個項的處理標誌位默認爲(ItemIsEnabled | ItemIsSelectable),coder可根據要求對不一樣屬性的項進行設置。在此設定第0列可編輯,其他列不可編輯。

程序運行結果,分別用TableView和ListView顯示相同的數據:

具體代碼以下:共有maindialg,mytablemodel,tack三個類,一個main運行類。具體界面文件是由Qt本身生成的ui。

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();
}

完整代碼:

相關文章
相關標籤/搜索