素人がpython(kivy)でブロック崩しを作ってみた話②

#あらすぎるあらすじ

[前回](https://qiita.com/guraragu0010/items/ab2ab4bf35467fc284e0)にひきつづいてブロック崩しができるまでを飽きるまで説明します。Widget treeの構成までをやりましたので、今回は配置されたWidgetにどのように関連性を持たせていくかを説明します。

#ロード トゥ ブロック崩し- Widget treeのWidget間に関係性を持たせてみよう-

　さて、そもそもWidget treeのWidget間に関係性を持たせるというのは何でしょうか。簡単な例をあげると、Widget treeに配置されたあるボタンを押すと、Widget tree内部の別のWidget(例えばラベルの値)が変化していくというようなことです。
　基本的には「色んなWidgetを使ってWidget treeを構成する⇒各Widget間に関係を持たせる」という流れで機能を持ったGUIを構成していくことになります。

##前回のwidget treeに関係を持たせる

　それでは、前回作ったWidget treeをそのまま使用して、Widget間の関係を構築していきます。以下に前回のWidget treeの結果と概念図を示します。今回は、button1(children1)を押すとlabel2に表示された数字が増えて、button2(children2)を押すと減るようにしてみましょう。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/9e3fc53e-225f-b666-e829-e9b6ad6f4343.png)

![widget_tree1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/a5a9f9b2-8b75-ed60-ee09-39b66647f7e8.png)


##label2に数字を表示する

まずは、label2に数字を表示するためにtestAppクラスのbuild関数を書き換えていきます。(後でButtonクラスのサブクラスplusButton、minusButtonを作るので、インスタンス生成もそれらに合わせて変更しています。)

```python:

class testApp(App):
	def build(self):
        #Boxlayout、plusButton、minusButton、Labelの生成
		layout1 = BoxLayout(orientation='vertical')
		button1 = plusButton(text='children1')
		layout2 = BoxLayout(orientation='horizontal')
		label2 = Label()
		button2 = minusButton(text='children2')
        #layout2の子Widgetとしてbutton2とlabel2を追加
		layout2.add_widget(button2)
		layout2.add_widget(label2)
		#layout1の子Widgetとしてbutton1とlayout2を追加
		layout1.add_widget(button1)
		layout1.add_widget(layout2)
		#Label2に初期値の表示
		label2.value = 100
		label2.text=str(label2.value)
		return layout1

```

　ほとんど前回と同様ですが、label2に持たせた変数valueに100という初期値を格納し、かつ、label2にvalueの値を文字列として表示するようにしています。

##ボタンを押す度にlabel2の値を変化させる

　次は今回のミソであるwidget間の関係を作るところです。Buttonを押すことでlabel2の値を変化させたいわけですが、単純なButtonにはそのような機能がないので、Buttonクラスのサブクラスを生成し、機能を追加していきます。この時に重要になるのがwidget tree内での相対位置です。以下がサブクラスの生成の部分となります。

```python:
#Buttonを押したときにlabel2の数値を増やす
class plusButton(Button):
    def on_press(self):
		#button1から見たときのlabel2の位置の指定
        label = self.parent.children[0].children[0]
		#labelの値と表示の変化
        label.value = label.value+1
        label.text = str(label.value)

#Buttonを押したときにlabel2の数値を減らす
class minusButton(Button):
    def on_press(self):
		#button2から見たときのlabel2の位置の指定
		#上との違いに注意
        label = self.parent.children[0]
		#labelの値と表示の変化
        label.value = label.value-1
        label.text = str(label.value)
```

　基本的にはButtonが押されたときの動作を表すon_pressを望ましい動作をするように定義していますが、今回はlabel2の値を変化させることが目的なので、on_press時にlabel2を呼び出す必要があります。ここでwidget treeの中の相対的な位置関係が必要となります。上記のプログラムをよく観察すると、plusbutton及びminusbutton(self)から見たときの位置関係からlabel2を呼び出しvalueの値を変化させるように指示していることが分かります。(下図参照)

![widget_tree2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/eeb8e795-d318-3e05-b4d4-bebf4225aad7.png)

![widget_tree3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/97641e22-badb-cf68-7467-b996d3f40036.png)


 このようにwidget treeの上部にある親widgetはparentで、下部にある子widgetはchildrenで指定することができます。また、childrenはリスト形式となっていますので、数値によって個別の子widgetを指定することができます。

##最終的な形。label2の値を変えてみよう

　準備は整いました。今までのことをまとめてlabel2の数値を変化させてみましょう。全体のプログラムと実行結果は以下のようになります。

```python:main.py

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout

#Buttonを押したときにlabel2の数値を増やす
class plusButton(Button):
    def on_press(self):
		#button1から見たときのlabel2の位置の指定
        label = self.parent.children[0].children[0]
		#labelの値と表示の変化
        label.value = label.value+1
        label.text = str(label.value)

#Buttonを押したときにlabel2の数値を増やす
class minusButton(Button):
    def on_press(self):
		#button2から見たときのlabel2の位置の指定
		#上との違いに注意
        label = self.parent.children[0]
		#labelの値と表示の変化
        label.value = label.value-1
        label.text = str(label.value)

class testApp(App):
	def build(self):
        #Boxlayout、plusButton、minusButton、Labelの生成
		layout1 = BoxLayout(orientation='vertical')
		button1 = plusButton(text='children1')
		layout2 = BoxLayout(orientation='horizontal')
		label2 = Label()
		button2 = minusButton(text='children2')
        #layout2の子Widgetとしてbutton2とlabel2を追加
		layout2.add_widget(button2)
		layout2.add_widget(label2)
		#layout1の子Widgetとしてbutton1とlayout2を追加
		layout1.add_widget(button1)
		layout1.add_widget(layout2)
		#Label2に初期値の表示
		label2.value = 100
		label2.text=str(label2.value)
		return layout1

testApp().run()

```

初期画面、右下(label2)の数値が100
<img width="602" alt="widget_tree4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/e61577b1-0a63-c9b8-2b37-4f3dd3818e1b.png">

各ボタンを押すたびに右下(label2)の数値が変化する
<img width="603" alt="widget_tree5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481391/0c4cfd11-f9e3-15ea-6fc6-b3f82fa2c823.png">


#まとめ
　今回はwidget treeの相対的な位置から他のwidgetを呼びだすことで、widget間に関係性を持たせて、GUIに機能を持たせました。これが分かれば簡単な計算機などを作ることができますね。
　次回はイベントか、KV言語について説明しようと思います。また次回に！

# 参考文献・web
 [原口和也 (2018)『実践Pythonライブラリー Kivyプログラミング -Pythonでつくるマルチタップアプリ―』久保幹雄,朝倉書店](https://www.asakura.co.jp/books/isbn/978-4-254-12896-3/)
 https://kivy.org/#home