どうもです、タドスケです。
Qt の レイアウトクラスの中で、おそらく一番使うであろう QBoxLayout 。
公式ドキュメントのページを読むと使える関数の一覧が載っていますが、説明が少ないため、「使ったらどうなるのか」がイメージしにくいです。
そこで、QBoxLayout の各機能を使った結果を、画像をまじえて紹介します。
本検証には PySide6 を使用しています。
QVBoxLayout と QHBoxLayout
QBoxLayout のサブクラスには QVBoxLayout と QHBoxLayout があります。
違いはウィジェットを並べる方向だけで、QVBoxLayout は縦方向、QHBoxLayout は横方向です。
QVBoxLayout | QHBoxLayout |
---|---|
関数の使い方については変わらないので、以降は QVBoxLayout を主に使用して説明します。
add○○ と insert○○ の違い
この後に紹介する関数で、add○○ / insert○○ とセットになっているものがあります。
両者の違いは、要素を追加する位置です。
add○○ は末尾に追加するのに対して、insert○○ は引数で指定した index の位置に挿入します。
既に要素が n 個ある場合、指定できる index の値は「0~n」となります。
n を超える値を指定すると、アプリがクラッシュするので注意(例外も出ない?)
それ以外の違いはないと思われますので、どちらか一方のみを紹介します。
addWidget / insertWidget
ウィジェットを子として追加します。
呼ぶたびに追加されていきます。
layout = QVBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(button3)
addLayout / insertLayout
別のレイアウトを子として追加します。
入れ子構造にすることで、複雑なレイアウトも作れます。
hlayout = QHBoxLayout()
hlayout.addWidget(QPushButton('HButton1'))
hlayout.addWidget(QPushButton('HButton2'))
layout.insertLayout(1, hlayout)
↑ のコードの例では、VBoxLayout の途中に HBoxLayout を挿入しています。
addSpacing / insertSpacing
次の要素までの間に空白を追加します。
layout.addWidget(button1)
layout.addSpacing(20)
layout.addWidget(button2)
layout.addSpacing(40)
layout.addWidget(button3)
↑ コードの例では、ボタン1と2の間に 20px , 2と3の間に 40px のスペースが追加されます。
addSpacerItem / insertSpacerItem
空白アイテムを追加します。
addSpacing は単に次要素との間隔を指定するだけでしたが、SpaccerItem はスペースの幅や拡縮の挙動(QSizePolicy)も指定できます。
layout.addSpacerItem(QSpacerItem(200, 50))
↑ コードの例では、幅 200px 、高さ 50px のスペースを追加しています。
ボタンの標準幅よりも大きい幅を指定したことで、ウィジェット全体が横に伸びているのに注目してください。
addStretch / insertStretch
親ウィジェットを拡縮した際に伸縮するための領域を追加します。
layout.addWidget(button1)
layout.addStretch(1)
layout.addWidget(button2)
layout.addStretch(2)
layout.addWidget(button3)
layout.addStretch(3)
引数の stretch を指定すると、addStretch を複数呼んだ場合の伸縮率を指定できます。
0 を指定すると、伸縮しなくなります。
↑ コードの例では、3つの領域の伸縮率を 1:2:3 に指定しています。
addStrut
レイアウトに対して垂直方向の最小サイズを制限します。
QVBoxLauout なら幅、QHBoxLayout なら高さが指定した値以下にならなくなります。
layout.addStrut(200)
最小幅を 200px に設定したことで、レイアウト全体の幅が 200px よりも小さくならなくなりました。
setContentsMargins
レイアウトの外周から内部のウィジェットまでの間隔を指定します。
引数は順に左、上、右、下で指定します。
layout.setContentsMargins(20, 30, 40, 50)
予め作っておいた QMargins オブジェクトを渡すこともできます。
margin = QMargins(20, 30, 40, 50)
layout.setContentsMargins(margin)
結果はどちらも同じです。
addItem / insertItem(QBoxLayout では無効?)
レイアウトアイテム(QLayoutItem)を追加します。
QLayoutItem にはアラインメント(Qt.AlignmentFlag)を指定できます。
しかし QBoxLayout でこの関数を呼ぶと未実装エラー(NotImplementedError)が発生します。
QBoxLayout を使う際には無視して良さそうです。
layout.addItem(QLayoutItem(Qt.AlignmentFlag.AlignTop))
# NotImplementedError
setDirection / direction
setDirection でウィジェットを追加する向きを設定します。
direction で現在の設定を取得します。
QVBoxLayout のデフォルト設定では上→下ですが、下→上 や 左→右 に変更することもできます。
(左→右に変更するくらいならQHBoxLayout 使ったほうが良いと思いますが)
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(button3)
layout.setDirection(QBoxLayout.Direction.BottomToTop)
print(f'Direction = {layout.direction()}')
# Direction = Direction.BottomToTop
↑ コードの例では、ウィジェットの向きを逆順(下→上)に変更しています。
ウィジェットを追加した後で呼んでも反映されます。
setStretchFactor / stretch
setStretchFactor で指定した子ウィジェット/レイアウトの伸縮率を設定できます。
addStretch と違って空白スペースを入れるのではなく、追加済みの子ウィジェット/レイアウト自体の伸縮率を設定する点が異なります。
予め子ウィジェット/レイアウト側に setSizePolicy を設定しておかないと正しく動きません。
stretch で現在の設定を取得します。
button1.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
button2.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
button3.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
layout.setStretchFactor(button1, 1)
layout.setStretchFactor(button2, 2)
layout.setStretchFactor(button3, 3)
print(f'Stretch1 = {layout.stretch(0)}')
# Stretch1 = 1
print(f'Stretch2 = {layout.stretch(1)}')
# Stretch2 = 2
print(f'Stretch3 = {layout.stretch(2)}')
# Stretch3 = 3
↑ コードの例では、追加済みのボタン1~3の伸縮率を 1:2:3 で設定しています。
サンプルコード
今回の検証で使用したコードを以下にアップしました。
コメントアウトする箇所を切り替えながら、結果の違いを比べてみてください。
コメント