Kivyを始めて一番最初にぶち当たった壁はなんですか?私は間違いなくwidgetの配置です。何故かwidgetの位置や大きさが思い通りになってくれないのです。例えば以下のcodeを見てください。
from kivy.app import runTouchApp
from kivy.factory import Factory
root = Factory.FloatLayout()
root.add_widget(Factory.Button(size=(100, 100), text='Push Me'))
runTouchApp(root)
私は以下のように画面左下にsizeが100x100のButtonが出る事を期待していたのですが
実際は
という風にWindow全体にButtonが広がってしまいました。inspectorで調べてみると
sizeが800x600になっている事が確認できます。何故でしょうか?原因はsize_hint
の事を考えてなかったからです。
位置や大きさに関するproperty
全てのwidgetが共通して持っているpropertyの内、位置や大きさに関する物が以下です。
非hint系 | hint系 | |
---|---|---|
位置 | pos x y right top center center_x center_y | pos_hint |
大きさ | size width height | size_hint size_hint_x size_hint_y size_hint_min size_hint_min_x size_hint_min_y size_hint_max size_hint_max_x size_hint_max_y |
たくさんあってややこしいですが、幾つかのpropertyは単に複数のpropertyをlistの形で扱えるように纏めただけなのでそれらの重複を除くと以下のように見やすくできます。
非hint系 | hint系 | |
---|---|---|
位置 | pos right top center | pos_hint |
大きさ | size | size_hint size_hint_min size_hint_max |
pos[0] == x
, pos[1] == y
, size[0] == width
, size_hint[1] == size_hint_y
, size_hint_min[0] == size_hint_min_x
といった具合の対応関係です。
上の表ではpropertyを非hint系
とhint系
の二つに分類していますが、これがどういう分類なのかと言うと
非hint系
は特に難しいことはなく只の位置や大きさを表す数値で単位はpixelです。hint系
はややこしくなっていて、まず hint系のpropertyは、その持ち主の親次第で意味が変わります。 冒頭の失敗例で言うなら
- Buttonの親はFloatLayoutなので、Buttonの持つhint系のpropertyの意味はFloatLayoutの流儀に従う
- FloatLayoutも実は親にWindowを持っているので、FloatLayoutの持つhint系のpropertyの意味はWindowの流儀に従う
ということです。次に hint系のpropertyには有効な状態と無効な状態があり、ほとんどのwidgetは既定でsize_hint(size_hint_x, size_hint_y)のみが有効になっています。 具体的にはそれぞれ
-
pos_hint
は既定値が空の辞書で、無効 な状態です。そして{'x': 0, 'right': .5}
のように非hint系の位置を表すpropertyの名前をkeyにして数値が入っている状態が 有効 です。 -
size_hint_x
とsize_hint_y
は既定値が1
で、 数値が入っている状態が 有効 です。None
だと 無効 。 -
size_hint_min_x
,size_hint_min_y
,size_hint_max_x
,size_hint_max_y
は既定値がNone
で、 無効 な状態です。数値が入っていると 有効。
となっています。この size_hintが既定で有効になっている事 がKivyにおいて最初に気を付けるべき所で、これによって親のwidget次第で既にsize
(width
, height
)による大きさの指定ができなくなっています。(冒頭の失敗例がそれ)。
最初に学ぶべきこと
というわけで最初に学ぶべきは、各種Layoutが子widgetのhint系propertyをどのように扱うかを知ることだと思います。まずはFloatLayout
とBoxLayout
からお薦めします。
冒頭の失敗例の修正
気付いているかもしれませんが、冒頭の失敗例はsize_hint
を無効にする事で期待通りの結果を得られます。
from kivy.app import runTouchApp
from kivy.factory import Factory
root = Factory.FloatLayout()
root.add_widget(Factory.Button(size=(100, 100), text='Push Me', size_hint=(None, None)))
runTouchApp(root)