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