第2章 Layoutを使ってみよう

2.1 なぜLayoutを使うのか

第1章ではボタンあるいはラベルがウィンドウに一つしか存在しませんでした。 では、次にボタンを二つ並べて表示してみましょう。次のようなコードを書いたとします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <QApplication>
#include <QPushButton>

int main(int argc, char** argv)
{
	QApplication app(argc, argv);
	QPushButton* button = new QPushButton("Hello Qt!");
	QPushButton* button2 = new QPushButton("Goodbye");
	button->show();
	button2->show();
	return app.exec();
}

このコードを実行すると、図2.1のようになります。


PIC 図 2.1: 実行結果 (on Windows)


本当はボタンが二つ並んで一つのウィンドウに収まってくれることを願っていましたが、これは予想外の結果です。

実は、一つのウィンドウには一つの部品しか表示できない のです。この一つの部品を親としましょう。 それではどのようにして複数のボタンを作ったらよいのでしょうか。

その方法は、一つの親を作りその中にどんどん部品を追加していけばよいのです。 この追加した部品を子とします。そうすれば、親の部品を表示することにより子も一緒に表示されます。

この親となるのがMainWindowであり、その中にLayoutをセットします。Layoutは部 品をどのように配置するかを管理するクラスです。

2.2 基本的なLayoutの使い方

Layoutにはいくつかの種類が存在します。最も良く使われるのが、QHBoxLayoutとQVBoxLayoutでしょう。 QHBoxLayoutのHはHorizontal、QVBoxLayoutのVはVertical であり、水平と垂直を意味しています。

実際使ってみたほうがわかりやすいので、とりあえず使い方を見てみましょう。 まずはQHBoxLayoutに3つのボタンを追加し、そのLayoutをメインウィンドウに表示させてみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>

int main(int argc, char** argv)
{
	QApplication app(argc, argv);
	QWidget* window = new QWidget;
	QPushButton* buttonA = new QPushButton("Button A");
	QPushButton* buttonB = new QPushButton("Button B");
	QPushButton* buttonC = new QPushButton("Button C");
	QHBoxLayout* layout = new QHBoxLayout;

	layout->addWidget(buttonA);
	layout->addWidget(buttonB);
	layout->addWidget(buttonC);

	window->setLayout(layout);
	window->show();	
	return app.exec();
}

3行目では<QHBoxLayout>をインクルードしています。 QHBoxLayoutを使うには、このヘッダーファイルが必要です。

8行目ではQWidgetクラスのwindowという変数を定義していますが、これがメインウィンドウ(親)となる変数です。 この中にレイアウトをセットすることで複数の部品を表示することができます。

14~16行目でボタンをレイアウトに追加しています。QHBoxLayoutはボタンを追加した順に水平に配置していきます。

17行目でウィンドウにレイアウトをセットしています。

これで完了です。実行した結果は図2.2のようになります。


image1 図 2.2: 実行結果 (on Windows)


QHBoxLayoutをQVBoxLayoutに変えてみてください。 QVBoxLayoutはボタンを追加 した順に垂直に配置していきます。実行結果は図2.3となります。


image2 図 2.3: 実行結果 (on Windows)


2.3 QGridLayout

QGridLayoutは名前の通り格子状に部品を配置していくLayoutです。 QGridLayoutに部品を追加する場合、QHBoxLayoutやQVBoxLayoutとは少し引数が違います。 次のコードを見てください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <QApplication>
#include <QPushButton>
#include <QGridLayout>

int main(int argc, char** argv)
{
	QApplication app(argc, argv);
	QWidget* window = new QWidget;
	QPushButton* buttonA = new QPushButton("Button A");
	QPushButton* buttonB = new QPushButton("Button B");
	QPushButton* buttonC = new QPushButton("Button C");
	QGridLayout* layout = new QGridLayout;

	layout->addWidget(buttonA,0,0);
	layout->addWidget(buttonB,0,1);
	layout->addWidget(buttonC,1,0,1,2);

	window->setLayout(layout);
	window->show();	
	return app.exec();
}

このコードを実行すると、図2.4となります。


image3 図 2.4: 実行結果 (on Windows)


addWidget関数が少し変わっています。 addWidgetの第1引数はボタンを配置を開始する縦の位置、第2引数は横の位置を表しています。 第3引数は縦の大きさ(例の場合ボタン1個分)、第4引数は横の大きさ(例の場合ボタン2つ分)を表しています (図2.5)。


image4 図2.5: GridLayout の配置


2.4 LayoutにLayoutを追加する(addLayout)

addLayout関数を使いLayoutにLayoutを追加することもできます。 次のコードを見てください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>

int main(int argc, char** argv)
{
	QApplication app(argc, argv);
	QWidget* window = new QWidget;
	QPushButton* buttonA = new QPushButton("Button A");
	QPushButton* buttonB = new QPushButton("Button B");
	QPushButton* buttonC = new QPushButton("Button C");
	QPushButton* buttonD = new QPushButton("Button D");
	
	QVBoxLayout* mainLayout = new QVBoxLayout;
	QHBoxLayout* layoutA = new QHBoxLayout;
	QVBoxLayout* layoutB = new QVBoxLayout;

	layoutA->addWidget(buttonA);
	layoutA->addWidget(buttonB);
	layoutB->addWidget(buttonC);
	layoutB->addWidget(buttonD);

	mainLayout->addLayout(layoutA);
	mainLayout->addLayout(layoutB);

	window->setLayout(mainLayout);
	window->show();	
	return app.exec();
}

この例では、mainLayoutを作りその中に二つのレイアウトを縦に配置しています。 実行結果は図2.6となります。


image5 図2.6: 実行結果 (on Windows)


2.5 メモリ管理について

さて、ここまで部品をnewした場合deleteをしていませんでした。 小さなプログラムでは少しくらいdeleteしなくても問題ありませんが、大規模なプログラムとなるとメモリリー クが心配です。

でも、今までbuttonAやbuttonB等作ってきましたが、これを全部deleteするのはとても面倒なことです。

実はこの事を心配する必要はありません。Qtでは親がdeleteされる時に一緒に子の部品も自動的にdelete してくれる仕組みとなっています。

よって必要なくなったら親のみdeleteすればよいでしょう。