2011年12月15日木曜日

( Qt C++ )カスタムモデルをQTableViewに表示する


今回はカスタムModelをQTableViewに表示します。
C++ GUI Programming with Qt4のサンプルをそのまま使うと動かないので一部変えて使用します。それではコードを

(C++ GUI Programming with Qt4 231ページを一部改変)

(currencymodel.h)
#include <QAbstractTableModel>

class CurrencyModel : public QAbstractTableModel
{
    Q_OBJECT//マクロ "Qtをはじめよう"か何かで確認してください。
public:
    explicit CurrencyModel(QObject *parent = 0);//コンストラクタ
    void setCurrencyMap(const QMap<QString, double> &map);
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
    QString currencyAt(int offset) const;
    QMap<QString, double> currencyMap;
};

(currencymodel.cpp)
#include "currencymodel.h"

CurrencyModel::CurrencyModel(QObject *parent) :
    QAbstractTableModel(parent)//ただparentを基本クラスに渡すだけ
{
}

int CurrencyModel::rowCount(const QModelIndex & /* parent */) const
{
    return currencyMap.count();//使わないのでparentはコメントアウトしている↑
}

int CurrencyModel::columnCount(const QModelIndex & /* parent */) const
{
    return currencyMap.count();//使わないのでparentはコメントアウトしている↑
}

QVariant CurrencyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    if (role == Qt::TextAlignmentRole) {
        return int(Qt::AlignRight | Qt::AlignVCenter);
    } else if (role == Qt::DisplayRole) {
        QString rowCurrency = currencyAt(index.row());
        QString columnCurrency = currencyAt(index.column());
        if (currencyMap.value(rowCurrency) == 0.0)
            return "####";
        double amount = currencyMap.value(columnCurrency)
                / currencyMap.value(rowCurrency);
        return QString("%1").arg(amount, 0, 'f', 4);
    }
    return QVariant();
}//ようはデータを返すもの

QVariant CurrencyModel::headerData(int section,
                                   Qt::Orientation /* orientation */,
                                   int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();
    return currencyAt(section);
}//ビューの行ヘッダとカラムヘッダを表示するために使う

void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
{
    currencyMap = map;
    reset();
}//QMapをフィールドのcurrencyMapにセット

QString CurrencyModel::currencyAt(int offset) const
{
    return (currencyMap.begin() + offset).key();
}//ようは通貨コードを返す

はい長いですね。ヘッダ部で重要なのはQAbstructTableModelを継承しているということです。cppのほうもあまり難しいことは行っていません。コメントの説明だけでわかるでしょう。
次にこれを使ってQTableViewに表示します。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)//uiにはGUI関連の記述がなされています。
{
    ui->setupUi(this);//GUI部品の初期化。QTableViewもここで初期化される。

    QMap<QString, double> currencyMap;
    currencyMap.insert("AUD", 1.3259);
    currencyMap.insert("CHF", 1.2970);
    currencyMap.insert("SGD", 1.6901);
    currencyMap.insert("USD", 1.0000);
    currencyMap.insert("JPN", 1.0000);

    CurrencyModel *cModel = new CurrencyModel();/*注意!newしてください。本の通りだと表示できません*/      
    cModel->setCurrencyMap(currencyMap);//作ったQMapをセット

    ui->tableView->setModel(cModel);//カスタムモデルをテーブルビューにセット
}

前回同様、uiにQTableViewや他のGUI部品の定義が既にしてあるものと考えてください。QMapでデータの元を作成し、それを先に作ったCurrencyModelにセットして、テーブルビューにセットして表示しています。

実行結果は以下のようになります。


かなり端折って書きました。後で加筆するかもしれません。
とりあえず以上です。


※加筆: モデルクラスの継承関係