Qt で上図の様に、ウィンドウにボタンなどの Widgit を配置する場合、QLayout オブジェクトを作成し、 そこに Wigit オブジェクトたちを追加し、QLayout オブジェクトをメインウィンドウに setLayout() する。

ソースコードは以下の様になる。

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget* window = new QWidget;
    QHBoxLayout *layout1 = new QHBoxLayout;             //  1行目のボタン列のための水平レイアウト
    QPushButton *b1 = new QPushButton("button&1");      //  ボタン1〜3 widgit オブジェクト生成
    QPushButton *b2 = new QPushButton("button&2");
    QPushButton *b3 = new QPushButton("button&3");
    layout1->addWidget(b1);                             //  ボタン1〜3 widgit オブジェクトをレイアウトに追加
    layout1->addWidget(b2);
    layout1->addWidget(b3);
    QHBoxLayout *layout2 = new QHBoxLayout;             //  2行目のボタン列のための水平レイアウト
    QPushButton *b4 = new QPushButton("button&4");      //  ボタン4〜6 widgit オブジェクト生成
    QPushButton *b5 = new QPushButton("button&5");
    layout2->addWidget(b4);                             //  ボタン4〜6 widgit オブジェクトをレイアウトに追加
    layout2->addWidget(b5);
    QVBoxLayout *layout = new QVBoxLayout;              //  レイアウトを縦に並べる垂直レイアウト
    layout->addLayout(layout1);                         //  1, 2 行目を垂直レイアウトに追加
    layout->addLayout(layout2);
    window->setLayout(layout);                          //  垂直レイアウトをメインウィンドウに setLayout()
    window->show();
    return app.exec();
}

やっていることは単純で分かりやすいのだが、ソースコードが妙に見づらい。
ソースが見づらいと、バグが発生しやすいし、修正を行う場合も修正箇所を認識するのが大変だ。

そこで、<< 演算子と | 演算子をオーバロードしてみた。

template<typename W>
QHBoxLayout &operator<<(QHBoxLayout &l, W &w)
{
    l.addWidget(&w);
    return l;
}
template<typename W>
QVBoxLayout &operator|(QVBoxLayout &l, W &w)
{
    l.addLayout(&w);
    return l;
}

これを使うと、先のソースは以下のようになる。

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget* window = new QWidget;
    QVBoxLayout *layout;                //  1,2行目を束ねる垂直レイアウト
    QHBoxLayout *layout1, *layout2;     //  ボタンを水平に配置する1,2行目の水平レイアウト
    *(layout1 = new QHBoxLayout) << *(new QPushButton("button&1"))
                                 << *(new QPushButton("button&2"))
                                 << *(new QPushButton("button&3"));
    *(layout2 = new QHBoxLayout) << *(new QPushButton("button&4"))
                                 << *(new QPushButton("button&5"));
    *(layout = new QVBoxLayout) | *layout1 | *layout2;
    window->setLayout(layout);                          //  垂直レイアウトをメインウィンドウに setLayout()
    window->show();
    return app.exec();
}

先のソースに比べて、行数も半分近くに減り、非常に見やすくわかりやすくなった。

ちなみに、演算子オーバロードの引数はポインタは不可で、参照でないとだめのようだ。

さらに、以下のように記述すれば、layout1, layout2 も省略できる。

    *(layout = new QVBoxLayout)
    	| *(new QHBoxLayout) << *(new QPushButton("button&1"))
                             << *(new QPushButton("button&2"))
                             << *(new QPushButton("button&3"))
    	| *(new QHBoxLayout) << *(new QPushButton("button&4"))
                             << *(new QPushButton("&Quit"));

ボタンが押された時の処理を指定したい場合、以下のようにボタンオブジェクトへのポインタを保持し、 QObject::connect() をコールしてやるとよい。

    QPushButton *quitButton;
    *(layout = new QVBoxLayout)
    	| *(new QHBoxLayout) << *(new QPushButton("button&1"))
                             << *(new QPushButton("button&2"))
                             << *(new QPushButton("button&3"))
    	| *(new QHBoxLayout) << *(new QPushButton("button&4"))
                             << *(quitButton = new QPushButton("&Quit"));
    QObject::connect( quitButton, SIGNAL(clicked()), &app, SLOT(quit()) );