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