Python+Kivy入門

kv言語のroot・self・app・app.rootを使ってウィジェットを参照する【Kivy入門】

この記事は約11分で読めます。

kv言語でウィジェットを参照するために使うroot・self・app・app.rootキーワードについて説明します。

ウィジェットを参照する3つのキーワード

kv言語ではウィジェットを参照するためのキーワードが3つあります。Pythonで使われているselfやsuperと似たようなもので、Kivyではウィジェットやクラスのインスタンスに対して使われますがどの立場から見たかでキーワードが変わってきます。

  • self:そのウィジェット自身を指します。Pythonコードの場合は通常のインスタンス参照になります。そのクラスのインスタンスやウィジェットを参照するために使うキーワードです。
  • root:アプリケーションのルートウィジェットを指します。rootはbuildメソッドで返されるウィジェットです。
  • app:現在実行中のアプリケーションのインスタンスを指します。Appクラスを継承して定義されたクラスのインスタンスです。

selfキーワード

Pythonコードの場合のselfは通常のインスタンス参照になり、そのクラスのインスタンスやウィジェットを参照するために使うキーワードです。Kvファイルの場合はウィジェット自身を指します。例えば、Labelウィジェットの定義の中でselfを使うと、そのLabel自身を指します。

example_keywords1.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class MyWidget(BoxLayout):
    def update_label1(self):
        # ルートウィジェットから見たLabelウィジェット
        self.ids.label1.text = "Label①のtextを変更したよ"

class ExampleKeywords1(App):
    def build(self):
        return MyWidget()

if __name__ == "__main__":
    ExampleKeywords1().run()

examplekeywords1.kv

<MyWidget>:
    orientation: "vertical"

    Label:
        id: label1
        text: "クリックしてみて"
        
    Label:
        id: label2
        text: self.text  # 自分自身のプロパティを参照
        on_touch_down: self.text = "クリックされたよ"  # 自分自身を更新

    Button:
        text: "押してみて"
        on_press: root.update_label1()

kvファイルから見たselfキーワード

ウィジェット自身のプロパティを参照したい時に使います。

text: self.text

自身のtextプロパティを参照しているので、キーワードはselfになります。

on_touch_down: self.text = "クリックされたよ"

自身のtextを更新しているので、キーワードはselfになります。

pythonから見たselfキーワード

Pythonから見たselfは現在のクラスのインスタンス (MainWidget)になります。つまり、rootから見てLabelやButtonは自身のツリー配下にあるのでMainWidgetから見たselfになります。

self.ids.label1.text = "Label①のtextを変更したよ"

LabelウィジェットはMainWidgetに属しているのでルートウィジェットから見るとselfになります。

rootキーワード

アプリケーションのルートウィジェットを指します。rootはbuildメソッドで返されるウィジェットを継承したサブクラスです。kvファイルでは定義されたルートウィジェットや他のウィジェットを指します。またルートウィジェットのインスタンス(Pythonコードで書いたウィジェットを継承したサブクラスのインスタンス)のメソッドなどを参照するために使います。

example_keywords2.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class MainWidget(BoxLayout):
    label_text = "これはルートウィジェットのクラス変数の文字列"

    def on_button_click(self):
        self.ids.mylabel.text = "rootのLabelのtextを変更したよ"

class ExampleKeywords2(App):
    def build(self):
        return MainWidget()

if __name__ == "__main__":
    ExampleKeywords2().run()

examplekeywords2.kv

<MainWidget>:
    orientation: 'vertical'

    Label:
        id: mylabel
        text: "ルートウィジェットから取得: " + root.label_text

    Button:
        text: "押してみて"
        on_press: root.on_button_click()

kvファイルから見たrootキーワード

kvファイルから見たrootはルートウィジェットになります。ここでのルートウィジェットはMainWidgetクラスです。

<MainWidget>
+--- BoxLayout
+---+--- Label
+---+--- Button

このサンプルコードは上記のtree構成になっています。記述されている場所のウィジェットから他のウィジェットを参照する場合はrootになります。つまり、Buttonから見たLabelはroot、Labelから見たButtonはrootになります。

MainWidgetのクラス変数やメソッドを参照する場合もrootになります。

text: "ルートウィジェットから取得: " + root.label_text

MainWidgetのlabel_text変数を参照しているのでキーワードはrootになります。

on_press: root.on_button_click()

MainWidgetのon_button_clickメソッドを呼び出しているので、キーワードはrootになります。

pythonから見たrootキーワード

この場合は自身がrootなのでselfに置き換わります。

self.ids.mylabel.text = "rootのLabelのtextを変更したよ"

LabelウィジェットはMainWidgetに属しているのでルートウィジェットから見るとselfになります。

appキーワード

appキーワードは、現在実行中のAppクラスのインスタンスを参照します。つまり、Appクラスで定義した変数やメソッドを参照する際に使われます。appを使うかどうかは設計によって変わってきます。selfやrootがローカルスコープでの参照をするのに対し、appはアプリ全体での操作に適しています。アプリケーション全体で使うデータやアプリを制御するメソッドを管理したい場合はAppクラスを継承したサブクラスに記述すると良いでしょう。

example_keywords3.py

from kivy.app import App

class ExampleKeywords3(App):
    app_value = "Appサブクラスの変数だよ"

    def on_button_press(self):
        self.root.ids.my_label.text = "ボタンが押されたよ"

if __name__ == "__main__":
    ExampleKeywords3().run()

examplekeywords3.kv

BoxLayout:
    orientation: "vertical"

    Label:
        id: my_label
        text: app.app_value  # Appサブクラスの変数を参照

    Button:
        text: "ボタン"
        on_press: app.on_button_press() # Appサブクラスのメソッドを呼び出す

kvファイルから見たappキーワード

Appサブクラスのクラス変数やクラスメソッドを参照する場合はappになります。

 text: app.app_value

Appサブクラスのクラス変数を参照しているのでキーワードはappになります。

 on_press: app.on_button_press()

Appサブクラスのクラスメソッドを参照しているのでキーワードはappになります。

Pythonファイルから見たappキーワード

Appサブクラスからルートウィジェットのウィジェットを参照するには「self.root」になります。次の章のapp.rootと同じ意味を持ちます。ここではappは自分自身になるのでself.rootになります。

self.root.ids.my_label.text = "ボタンが押されたよ"

app自身が持っているルートオブジェクトに属するLabelウィジェットを参照するため、キーワードは「self.root」になります。

app.rootキーワード

違うクラスの参照やツリー構成の階層が深いとスコープや親子関係の理由で参照できない場合があります。その時はapp.rootを試してみてください。app.rootは現在実行中のアプリケーションインスタンス(app)のルートウィジェット(root)を参照します。つまりapp.rootを使うことで、appを経由してrootにアクセスできます。

以下にapp.rootを確認するサンプルコードを示します。コンソール上にメッセージが表示されます。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.widget import Widget

# Pythonファイル内でkv言語を直接記述
kv_code = '''
<MyWidget>:
    Button:
        text: "押してみて"
        on_press: app.root.other_widget.scope_test1()
'''

Builder.load_string(kv_code)

class OtherWidget(Widget):
    def scope_test1(self):
        print("OtherWidgetを参照")
        app = App.get_running_app() #現在のアプリケーションインスタンスを取得
        app.root.scope_test2()

class MyWidget(BoxLayout):
    other_widget = OtherWidget()  # OtherWidgetのインスタンスを作成

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.add_widget(self.other_widget)  # OtherWidgetをMyWidgetに追加

    def scope_test2(self):
        print("MyWidgetを参照")

class ExampleKeywords4(App):
    def build(self):
        return MyWidget()

if __name__ == "__main__":
    ExampleKeywords4().run()

OtherWidget()から他のクラスに直接アクセスできないのでapp.rootを使用します。

app.root.other_widget.scope_test1()

kvコードでは、ルートウィジェットであるMyWidget()から、スコープ外のOtherWidget()のscope_test1メソッドを呼び出しているので、app.rootを使用しています。インスタンス変数のother_widgetにはOtherWidget()のインスタンスが代入されているので、名前空間の順に呼び出すと上記の書き方になります。

Appアプリケーション→ルートウィジェット→OtherWidget()のインスタンス→OtherWidget()のメソッド

        app = App.get_running_app() #現在のアプリケーションインスタンスを取得
        app.root.scope_test2()

Pythonコードでは、OtherWidget()から見てExampleKeywords4()はスコープ外なので参照できません。その為、Appサブクラスを参照するためにAppのインスタンスを取得する必要があります。Appのインスタンスを取得するにはApp.get_running_app() を使用します。ここではappインスタンス変数に代入しています。後はこれらを名前空間の順番に呼び出すだけです。

Appアプリケーション→ルートウィジェット→MyWidget()のメソッド

app.rootを使用した良い例が下記の記事にあるので合わせてご覧ください。

まとめ

このようにどのウィジェットから見たかでキーワードが異なりますので注意してください。

Kivyのself,root,appキーワードの関係図
  • 自身のウィジェットはself
  • 自身以外を参照するときはrootapp
  • ルートウィジェットから見たウィジェットはself
  • Appからウィジェットを参照する場合は、self.root

Comment

タイトルとURLをコピーしました