2014/01/07

QTableViewへ登録するQStandardItemにでユーザ定義型をくるませる

QTableView等のQ*View系のQt Model/View構造で管理されているビューを使用する場合、 もっとも簡単な使い方として、QStandardItemModelへQStandardItemをセットしていく事になる。

  • QStandardItem = Table等に表示される1項目
  • QStandardItemModel = Itemの集合(row/column/parent/childの概念)

この際に、Tableのセルに表示させる文字列(QString)以外にユーザ定義型をQStandardItem::setDataを使って格納することができる。

個人的にはクラスのポインタを各Itemに格納させておいて、TableView(or ListView)でDrag&Dropして順番を入れ替えた後、 入れ替えた順番でクラスのポインタを順にとってくるという事をしたかった。

このサイト(QVariant の使い方)によるとポインタはもたせられなくてvoidにしなさいとあるんだが、実際にはvoidにしてもうまくいかなかったので追加調査

参考にしたのは以下の2つのサイト

今回はポインタだったので不要だったかもしれないが、こちらのサイトによるとユーザ定義型の場合は追加で以下の3つが必要となるよう。

  • QObjectの継承
  • コピーコンストラクタの定義
  • 代入演算子の定義

以下ではMyClassのconstポインタをQStandardItemに格納している。

まず、下準備として以下が必要。

// const MyClass*をQMetaTypeとして使いますよという宣言
Q_DECLARE_METATYPE(const MyClass*);

// 以下のoperator定義はDrag&Dropをしたい場合に必要
// もしやらないと、"QVariant Invalid type to save" のようなエラーが大量にでる
// see. https://qt-project.org/forums/viewthread/22238
QDataStream& operator<<(QDataStream& out, const MyClass* const& rhs)
{
    out.writeRawData(reinterpret_cast<const char*>(&rhs), sizeof(rhs));
    return out;
}
QDataStream& operator >> (QDataStream& in, const MyClass*& rhs)
{
    in.readRawData(reinterpret_cast<char*>(&rhs), sizeof(rhs));
    return in;
}

// const MyClass*をQMetaTypeとして使う前(たとえばコンストラクタ)に以下を書く
MyApp::MyApp(){
    qRegisterMetaTypeStreamOperators<const MyClass*>("const MyClass*");
}

そして、実際に値をセットするときは

void MyApp::setData(QList<MyClass*> myClasses){
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(myTableView->model());

    foreach(const MyClass* class, myClasses) {
        QStandardItem* item = new QStandardItem(class->name());
        item->setData(QVariant::fromValue(class));
        model->appendRow(item);
    }
}

な感じでセット(myTableView => QTableView*ね)

逆に値を引っ張ってくる時は

QList<MyClass*> MyApp::getData(){
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(myTableView->model());

    QList<const MyClass*> myClasses;
    const int COLUMN_NO = 0;// setDataでMyClass*を格納したQStandardItemが入っているColumn番号 = 0
    for (int i = 0; i < model->rowCount(); i++) {
        myClasses.push_back(model->item(i, COLUMN_NO)->data().value<const MyClass*>());
    }
    return myClasses;
}

のような感じで取得できる。


0 件のコメント: