備忘録

何かあったとき用に

KivyでPythonのみ使用して色んなものを実装する

Kv LanguageをPython側でどう処理されてるか見るためにPythonのみで色々実装しようとしたら失敗続きで2日程悩んだので自戒をこめて書いとく。

Button実装

main.py:

from kivy.app import App
from kivy.uix.button import Button


class MainApp(App)
    def build(self):
        pass

main.kv:

Button:
    text: "hoge"

from kivy.app import App


class MainApp(App):
    def build(self):
        return Button(text="hoge")

と書き換えられる。

Labelも同じ感じなので割愛

Buttonを押したときのEvent処理

Python Kivyの使い方① ~Kv Languageの基本~の10項を例にする。
今回はクラスを新たに作らず全てMainAppクラス内で済ませるようにした。(正直、新しくクラス作ったほうが可読性は上がる)

main.py:

from kivy.app import App
from kivy.properties import StringProperty


class MainApp(App):
    text = StringProperty()
    btn_text = StringProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.text = ""
        self.btn_text = "Button"

    def build(self):
        pass

    def pressed(self):
        if self.text != "":
            self.text = ""
            self.btn_text = "Blank"
        else:
            self.text = "Hello World"
            self.btn_text = "Changed"

main.kv:

BoxLayout:
    orientation: 'vertical'
    size: root.size

    Label:
        id: label1
        font_size: 68
        text: app.text

    Button:
        id: button1
        text: app.btn_text
        font_size: 68
        on_press: app.pressed()

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

class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.label = Label(text="", font_size=48)
        self.button = Button(text="Button", font_size=48, on_press=self.pressed)

    def pressed(self, *args):
        if self.label.text != "":
            self.label.text = ""
            self.button.text = "Blank"
        else:
            self.label.text = "Hello World"
            self.button.text = "Changed"

    def build(self):
        boxlay = BoxLayout(orientation="vertical")
        boxlay.add_widget(self.label)
        boxlay.add_widget(self.button)
        return boxlay

と書き換えられる。

ここで注意が2つある。

一つは

self.button = Button(text="Button", font_size=48, on_press=self.pressed)

on_press=self.pressed()とはしないこと。
この場合、Event: on_pressの値をcallback関数に指定する必要があり、self.pressed()だと返された(returnで返ってきた)値を代入してしまうこととなる。

もう一つは

def pressed(self, *args):

で必ず引数を(使わずとも)追加する必要がある。理由としては、pressed関数はcallback関数なので引数に自身のインスタンス(self)ともう一つ、呼んだ関数のインスタンス(この場合MainApp())を必要とする。そのため、pressed関数を利用するためにはこの場合2つの引数が必要となる。 呼んだ関数のインスタンスを利用したい場合は*argsinstanceとかに変えれば良い。使わないなら基本的に引数は*argsで十分。

参考:
公式リファレンス - Button (英語)

また、pressed関数に他の引数を追加したい場合はfunctoolsモジュールからpartialをimportして

self.button = Button(text="Button", font_size=48, on_press=partial(self.pressed, <arg1>, <arg2>...)

とする。(self.pressed(<arg1>, <arg2>...)は先述したとおりreturnされた値を代入してしまう。)
そしてpressed関数を

def pressed(self, instance, <arg1>, <arg2>, ...):

とする。

LabelまたはButtonのtextを変えたい場合は

self.label = Label(text="", font_size=48)
self.button = Button(text="Button", font_size=48, on_press=self.pressed)

のように変数を作り、

self.label.text = ""
self.button.text = "Blank"

のようにクラス変数の値を変えれば良い。

今回示した例とけっこう違う方法で実装することも可能なので、随時更新していきたい。