Kivy小ネタ集(随時更新)

<!--
# 既に指を離しているかを判定

`on_touch_up`のようなeventの形ではなくflagでほしい時は

```python3
既に指を離しているか = touch.time_end != -1
```

とすれば良いようです。
-->

# PyInstallerを使う際に必要そうな事

私はPyInstallerを使ったことがないので動作未確認ですがよく見かけるので貼っておきます。

```python
if not sys.stderr:
    os.environ['KIVY_NO_CONSOLELOG'] = '1'

from kivy.resources import resource_add_path

if getattr(sys, 'frozen', False):
    resource_add_path(sys._MEIPASS)
```

# markupのtagがあるとそこが優先的に折り返されてしまう

```python3
from kivy.app import runTouchApp
from kivy.lang import Builder

KV_CODE = '''
Label:
    markup: True
    text: '[color=#00FF00]Kivy[/color]は楽しい'
    text_size: self.width, None
    font_size: 50
    font_name: 'yomogifont.otf'
'''

runTouchApp(Builder.load_string(KV_CODE))
```

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144673/ed77f89e-c29f-f75a-bbfd-10b3bde42857.png)
windowの幅を縮めると
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144673/ebf4ba0d-3bff-27a2-5a48-906341e882f2.png)



# software keyboardがTextInputを覆ってしまって入力中の文字が見えなくなる問題への対処

```python3
from kivy.core.window import Window
Window.softinput_mode = 'below_target'
```

[情報源の動画](https://www.youtube.com/watch?v=sa4AVMjjzNo)

# mouseのbuttonを押し下げていない時にもcursorの座標を得たい時はWindow.mouse_pos

(2023/10/03 追記) 現在は[Event Manager](https://kivy.org/doc/master/api-kivy.eventmanager.html)という物を用いるのが正攻法のようです。

多分desktop環境限定ですが`Window.mouse_pos`にはbuttonを押し下げているかどうかに関わらず常にmouse cursorの座標が入っているようです。注意点として座標はWindow座標系で表されているので、widgetと衝突判定したいなら例えば以下のように座標変換が必要です。

```python3
from kivy.core.window import Window

def on_mouse_pos(window, mouse_pos):
    if some_widget.collide_point(*some_widget.parent.to_widget(*mouse_pos)):
        print('衝突しました')
Window.bind(mouse_pos=on_mouse_pos)
```

[Youtube](https://youtu.be/ZW8-5EG4pDU)

# `on_touch_down`時の正確な位置が知りたければ`pos`ではなく`opos`を

`ScrollView`や`DragBehavior`のようなdrag操作を受け付けるwidget/behaviorがwidget階層の中にある時、`on_touch_down`時の`touch.pos`が正しい値ではなくなる場合があります。なので`on_touch_down`時は常に`opos`を利用するようにしておくと安全です。

# `__init__()`内でKv言語で書いた物が使える保証はない

以下のように定義されたwidgetがある時、

```python3
class MyWidget(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.ids.label.text = 'Hello'  # A

Builder.load_string('''
<MyWidget>:        # B
    Label:         # B
        id: label  # B
''')
```

このwidgetを以下のように作ることはできますが

```python3
widget = MyWidget()
```

以下のようには作れません。

```python3
widget = Builder.load_string('''
Widget:
    MyWidget:
'''
```

後者ではA行が実行された時にはBがまだ適用されていない為です。そしてこの問題に対応する為には以下のように書き換える必要があります。

```python3
class MyWidget(Widget):
    def on_kv_post(self, *args, **kwargs):
        super().on_kv_post(*args, **kwargs)
        self.ids.label.text = 'Hello'
```

`on_kv_post`はeventとして実装されているのでKv言語内で以下のように使う事もできて便利です

```yaml
何かのWidget:
    何かのWidget:
        id: hoge
    何かのWidget:
    何かのWidget:
        on_kv_post: print(hoge)
```


# propertyのbindingが行われる条件

### bindingがうまくいかない例
以下のコードは`TextInput`に書いた文字列がそのまま`Label`に表れるだけの単純な物ですが

```python3
from kivy.lang import Builder
from kivy.app import runTouchApp

layout = Builder.load_string('''
BoxLayout:
    TextInput:
        id: ti
    Label:
        text: ti.text
''')

runTouchApp(layout)
```
![](https://qiita-image-store.s3.amazonaws.com/0/144673/47454a3d-d01b-c1b8-2603-c7b135ef423a.png)

例えば`Label`に表れる文字列を全て大文字にしようとして以下のように書き換えると

```python3:import文は省略
layout = Builder.load_string('''
BoxLayout:
    TextInput:
        id: ti
    Label:
        text: ti.text.upper()  # 変更点
''')

runTouchApp(layout)
```
bindingは行われず`TextInput`に何を書こうとも`Label`には何も表れなくなります。
![](https://qiita-image-store.s3.amazonaws.com/0/144673/f4bc7b21-ec41-1dd3-9228-074ada5d8fca.png)
これはKv言語の解析器が、ドットで連なった識別子の末端がKivyのpropertyである場合でのみbindingを行うからと思われます。(`ti.text`はKivyのpropertyですが`ti.text.upper`は関数なのでbindingされなかった)。

### 対策

なので以下のように末端を`text`にしてしまえば

```python3
layout = Builder.load_string('''
BoxLayout:
    TextInput:
        id: ti
    Label:
        text: str.upper(ti.text)
''')

runTouchApp(layout)
```

無事bindingが行われます。
![Screenshot at 2019-03-27 21-23-59.png](https://qiita-image-store.s3.amazonaws.com/0/144673/09d3bddc-7cee-c02c-a5cc-0d607fc80312.png)

### spaceを使った技

面白いのが、Pythonでは `a = 'aaa'.upper()` を `a = 'aaa' .upper()`という風にspaceを置く書き方も許されているわけですが、これを利用した場合でも

```python3
layout = Builder.load_string('''
BoxLayout:
    TextInput:
        id: ti
    Label:
        text: ti.text .upper()
''')

runTouchApp(layout)
```

bindingが行われます。
![Screenshot at 2019-03-27 21-23-59.png](https://qiita-image-store.s3.amazonaws.com/0/144673/09d3bddc-7cee-c02c-a5cc-0d607fc80312.png)
spaceを置いた為に、解析器は`text`が末端であると思い込みbindingしてしまったのでしょう。

### 文字列リテラル内はbindingの対象外

Python3.6で導入された`f-strings`を使うと

```python3
layout = Builder.load_string('''
BoxLayout:
    TextInput:
        id: ti
    Label:
        text: f'{ti.text}'
''')

runTouchApp(layout)
```

bindingされません。
![](https://qiita-image-store.s3.amazonaws.com/0/144673/f4bc7b21-ec41-1dd3-9228-074ada5d8fca.png)
ただ代わりに`str.format()`を使えば解決できます。

(この[PR](https://github.com/kivy/kivy/pull/7371)によって開発版ではf-string内でもbindingが行われます。)

# KivyMDの公式repositoryを使ってはいけない

KivyMDの公式repositoryはGitlabにある[これ](https://gitlab.com/kivymd/KivyMD)で、もう更新はされてなくていくつか不具合が残ったままになっています。なので代わりに開発が盛んな[このrepository](https://github.com/kivymd/KivyMD)を使う事を薦めます。

```text:install方法
$ pip install kivymd
```

# Animationは複数の物を同時にアニメーションできる

```python
anim = Animation(...)
anim.start(widget1)
anim.start(widget2)
```

のような事をしても大丈夫です。

# ~~SequenceとParallelはBugの宝庫~~

~~Animation同士を足した時に作られる`Sequence`とAnimation同士を&演算した時にできる`Parallel`はかなりBugが多いです。それらを直すPullRequestを出してはいますが、まだ採択されていません。~~ 最新版では多くのbugが修正済みです。

# gardenのmoduleをprojectのdirectory内に含めてしまう方法

普通に`garden install xxxx`とするとinstall先は`<ユーザーのホームディレクトリ>/.kivy/garden`になり仮想環境による分離がなされませんが、`garden install --app xxxx`とするとinstall先は`<カレントディレクトリ>/libs/garden`になり`<カレントディレクトリ>`内の`.py`を立ち上げた時にのみ利用可能な状態になります。なのでproject毎に分離された環境へgardenをinstallできるわけです。

# アプリのデータの保存先

は[App.user_data_dir](https://kivy.org/docs/api-kivy.app.html#kivy.app.App.user_data_dir)を使うのが便利です。

# Android向けへのPackagingに関して

Kivyはマルチプラットホームを謳っていますが、いくつか注意点があり

- AndroidのAPKを作るにはLinuxが要り(追記: MacOSXでも可能なようです)
- iOS向けへのPackagingにはMacOSXが要ります

~~私はMaxOSXは持っていないのでiOS向けへのPackagingに関しては分かりませんが、少なくともAndroid向けへのPackagingは地獄のように難しいです。又、Androidに持って行く場合は使えるPythonのVersionの選択肢も狭いです。一応私が成功しているのは今の所 2.7.2 と 3.5.0 だけで、3.6系ではまだ一度もうまくいってません。なのでもしAndroidへ持っていく予定があるなら、簡単なHelloWorldでいいので自分がどのversionのPythonでのPackagingに成功するか確かめた上で、Projectで採用するPythonのversionを決めるといいと思います。~~
また使えるPythonのversionの選択肢が狭いです。現在(2019/03/22)もしPython3系を使いたいならPython3.7.1の一択です。なので開発PC側でも3.7.1を使うべきだと思います。

# kivy.config

`kivy.config.Config`を使うことで、Kivyの様々な設定をいじる事ができます。例えば描画の最大フレームレートを20にしたいなら

```python
from kivy.config import Config
Config.set('graphics', 'maxfps', 20)
```

とします。設定できる値の一覧は`<ユーザーのホームディレクトリ>/.kivy/config.ini`を見るとわかります。以下が私の`config.ini`の一部で

```text
[graphics]
display = -1
fullscreen = 0
height = 600
left = 0
maxfps = 40
multisamples = 2
position = auto
rotation = 0
show_cursor = 1
top = 0
width = 800
resizable = 1
(略)
[modules]
```

これを見て自分が作るアプリに適した設定が行えます。

```python
from kivy.config import Config
Config.set('modules', 'inspector', '')  # Inspectorを有効にする
Config.set('graphics', 'width', 1280)  # Windowの幅を1280にする
Config.set('graphics', 'height', 720)  # Windowの高さを720にする
Config.set('graphics', 'maxfps', 20)  # フレームレートを最大で20にする
Config.set('graphics', 'resizable', 0)  # Windowの大きさを変えられなくする
```

もちろん`config.ini`自体を書き換える事もできますが、その場合はそのユーザーが実行するすべてのKivyプログラムに影響を及ぼすので注意してくだい。また幾つかのmoduleは初期化の際にこの設定値を参照しているので、ちゃんと設定値を反映させたいなら必ず **他のKivy関係のmoduleのimportに先立って書き換えてください** 。

```python
from kivy.config import Config
Config.set(...)
Config.set(...)
# ここで他のKivy関係のmoduleをimport
```

### 私が書き換えた事のある設定値

#### log関係

Android端末で動くアプリケーションのlogは`logcat`を使って見るのが普通だと思いますが、訳あってそれが使えない時は以下のようにして実機上にlogを書き出させています。

```python
Config.set('kivy', 'log_dir', '/mnt/sdcard/kivy_logs')
Config.set('kivy', 'log_enable', 1)
```

また原因不明のBugに悩まされた時は一時的にlogのレベルをあげています。

```python
Config.set('kivy', 'log_level', 'debug')  # または'trace'
```

#### graphics関係

```python
Config.set('graphics', 'fullscreen', 1)  # Fullscreen
Config.set('graphics', 'width', 1280)  # Windowの幅
Config.set('graphics', 'height', 720)  # Windowの高さ
Config.set('graphics', 'maxfps', 20)  # 最大フレームレート
Config.set('graphics', 'resizable', 0)  # Windowの大きさを変えられなくする
```

上の５つの設定値の内、`maxfps`以外はAndroidでは意味をなさないことに注意してください。Android上では(おそらくiOSもですが)常にモニター全体を使ったfullscreenで実行されるからです。(この理解はもしかすると間違ってるかもしれないので、いつか調査するかもしれません。)

#### Scroll関係

```python
import kivy.utils

if kivy.utils.platform in ('linux', 'win', 'macosx', ):
    Config.set('widgets', 'scroll_timeout', 400)  # 既定値は250
    # Config.set('widgets', 'scroll_distance', 20)  # 既定値は20
```

`ScrollView`はこの値を使って通常のtouchとscrollを区別しています。具体的には、画面に指を触れてから(mouseのボタンを押し下げてから)`scroll_timeout`ミリ秒以内に`scroll_distance`sp 以上動いた時のみscrollとして認識されます。また`DragBehavior`もこの値を通常のtouchとdragの区別に用いています。

上記のコードのように実行環境がLinux,Windows,MacOSXである時のみ(つまりはdesktop環境である時のみ)`scroll_timeout`を増やしている理由ですが、私が利き手じゃない方の手でmouseを操作しているせいかよくscrollに失敗して通常のtouchになってしまうからです。

#### modules

```python
Config.set('modules', 'inspector', '')
Config.set('modules', 'touchring', 'image=好きな画像.png')
```

この値については[この記事](https://qiita.com/gotta_dive_into_python/items/caa3e0f41ddfaedcdb95)を参照してください。

### KCFG_ 環境変数

上で述べたconfigの値は環境変数からも[いじれる](https://kivy.org/doc/master/guide/environment.html#configuration)。例えば`Config.set('graphics', 'maxfps', 0)`は環境変数`KCFG_GRAPHICS_MAXFPS`を`0`に設定することでも可能で、自動テストの際に役に立つ。

# よく見かける間違い1 Builder.load_string()及びBuilder.load_file()の戻り値を受け取っていない

Kv言語には２種類のwidgetの定義方法があり、それは`root rule`と`class rule`です。書いたKv言語のコードに`root rule`が含まれている場合、それを読み取った`Builder.load_string()`及び`Builder.load_file()`は`root rule`で定義されたwidgetのinstanceを返すのですが、それを受け取らずに捨てている人をよく見かけます。結果`root rule`に書いたものが全て無駄になります。

# よく見かける間違い2 Kivyのpropertyをclass属性として扱っている

Kivyのpropertyは以下のように

```python3
from kivy.event import EventDispatcher
from kivy.properties import StringProperty, NumericProperty

class Book(EventDispatcher):
    title = StringProperty()
    price = NumericProperty()
```

class属性の位置で作るせいなのか、そのままclass属性として使っている人をときどき見ます。

```python3:非常にまずい例
Book.title = 'Fluent Python'
Book.price = 5000
print(Book.title)  # => Fluent Python
print(Book.price)  # => 5000
```

上のような書き方をしてしまうと、何も怒られないまま`title`と`price`が本当に只のclass属性に置き換わってしまうので危険です。必ずinstance属性として扱うべきです。

```python3
book1 = Book(title='Fluent Python', price=5000)
book2 = Book(title='Dive Into Python 3', price=100)
print(book1.title)  # => Fluent Python
print(book1.price)  # => 5000
print(book2.title)  # => Dive Into Python 3
print(book2.price)  # => 100
```

詳しくは[この記事](https://qiita.com/gotta_dive_into_python/items/b7d8d19dd49599182c9d#property%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%9D%E3%81%AE%E3%82%82%E3%81%AE%E3%82%92%E6%89%B1%E3%81%86)に書きました。

# 間違ったkeyword引数を渡した時のerrorが不親切

Python3を使っている場合、上で定義したBookに渡すkeyword引数を以下のように打ち間違えると

```python3
book = Book(title='Hoge', plice=5000)
```

```text:error
 Traceback (most recent call last):
   File "/somewhere/main.py", line 21, in <module>
     book = Book(title='Hoge', plice=5000)
   File "kivy/_event.pyx", line 254, in kivy._event.EventDispatcher.__init__ (/tmp/pip-build-1ulcgpqm/kivy/kivy/_event.c:4922)
 TypeError: object.__init__() takes no parameters
```

と怒られます。この `object.__init__() takes no parameters`が出たら十中八九渡すkeyword引数のkeyが間違っています。またPython2だとこれに対して何も怒らないため、さらにたちが悪いです。

# widgetのクラス名は大文字から始め、Kivyのproperty名は小文字かアンダーバーで始める

この命名規則はKv言語を用いない場合は守らなくても動くようですが、用いる場合は強制です。理由はKv言語の解析器がそれでpropertyとwidgetを区別しているからです。

# Kv言語内でのproperty名の打ち間違いには何もerrorを出してくれない

以下のように「text」を「textt」と打ち間違えても

```python3

from kivy.app import runTouchApp
from kivy.factory import Factory
from kivy.lang import Builder


root = Builder.load_string(r'''
Button:
    textt: 'Hoge'
''')

runTouchApp(root)
```

何も怒ってくれません。これは__存在しないproperty名に出会ったら新たなpropertyの作成とみなすというKv言語の(個人的にあまり良くないと思う)仕様__によるものです。実際inspectorで見てみると

![Screenshot at 2018-02-11 00-18-36.png](https://qiita-image-store.s3.amazonaws.com/0/144673/d72912e3-f182-6c77-7992-e38acddcecaf.png)

「textt」というpropertyが出来ているのが確認できます。[既存のpropertyへの値の設定]と[新しいpropertyの作成]は異なる文法の方が良かったと思います。

# Appクラスの名前から自動でKvファイルを読みに行く仕組みを使うべきか

Kivyのdocumentationを読んでいると最初の方でこの仕組みを教えられるのですが、個人的にはこれは使わなくてもいいかなという感じです。以下のようにこの仕組みを使った場合と

```python3:main.py
from kivy.app import App

class TestApp(App):
    pass

TestApp().run()
```

```text:test.kv
FloatLayout:
    Label:
        text: 'Hello World'
```

以下のように使わなかった場合とだと

```python3:main.py
from kivy.app import App
from kivy.lang import Builder

class TestApp(App):
    def build(self):
        # 注意: kvファイルの名前を"test.kv"以外にしないといけない。
        # もし"test.kv"のままだと此処で手動で読み込むのに加えてAppクラスが自身の名前から自動で読み込むため
        # 二重に読み込まれてしまう。
        return Builder.load_file('./main.kv')

TestApp().run()
```

```yaml:main.kv
# test.kvと同じ
```

どっちが良いかですが、私は後者の方が何をやっているのか分かり易いので好きです。また以下のように

```python3:main.py
from kivy.app import App
from kivy.lang import Builder

KV_CODE = r'''
FloatLayout:
    Label:
        text: 'Hello World'
'''

class TestApp(App):
    def build(self):
        return Builder.load_string(KV_CODE)

TestApp().run()
```

.pyファイルの中に.kvの中身を含めてしまう手もあり、これもパッと見て何をしているのか分かり易いので好きです。ただこの方法だと使っているEditorがKv言語の色付けに対応していても使えないという短所があります。

# animationできる物の最低条件

(ここでいう「animationできる物」とは「`kivy.animation.Animation`でanimationできる物」という意味です)

[公式の説明](https://kivy.org/docs/api-kivy.animation.html)を読むとwidgetをanimationする例しか載ってないのでwidget専用の物と思いがちですが、実はその適用範囲は広いです。その例の一つが[これ](https://github.com/kivy/kivy/blob/93dd922bd32e9b6144466053df6755313554fb34/kivy/tests/test_animations.py#L67-L73)で、描画命令classのinstanceをanimationの対象にしているのが分かります。この「animationできる物」は突き詰めていくと以下のようになります。

以下のような`kivy.animation.Animation`のinstanceがある時、

```python3
from kivy.animation import Animation

anim = Animation(value=1)
```

これのanimation対象としての最低条件を満たす物は

```python3
from kivy.event import ObjectWithUid

class Minimum(ObjectWithUid):  # A
    pass

anim_target = Minimum()
anim_target.value = 0  # B
```

です。**`ObjectWithUid`のsubclassで(A行)**かつ**animation対象の属性(又は属性のように読み書きできる物)であるvalueを持っていれば(B行)**何でもいけます。実際に以下のコードで確かめてみると

```python3
from kivy.animation import Animation
from kivy.app import App
from kivy.factory import Factory
from kivy.event import ObjectWithUid

class Minimum(ObjectWithUid):

    def __init__(self):
        self._value = 0

    def _get_value(self):
        print('_get_value', self._value)
        return self._value

    def _set_value(self, value):
        print('_set_value', value)
        self._value = value

    value = property(_get_value, _set_value)

class TestApp(App):

    def build(self):
        return Factory.Widget()

    def on_start(self):
        self._anim_target = anim_target = Minimum()
        Animation(value=1, step=0.5, duration=3).start(anim_target)


TestApp().run()
```

ちゃんとanimationしている事が確認できます。

```text:標準出力
_get_value 0
_set_value 0.0
_set_value 0.1662893669999903
_set_value 0.3324920220002241
_set_value 0.49867277366683993
_set_value 0.6648306916667934
_set_value 0.8310590653333444
_set_value 0.9975033390001045
_set_value 1.0
```

#### Class図

![Untitled Diagram.png](https://qiita-image-store.s3.amazonaws.com/0/144673/3fb2e19b-b556-9c94-ef74-09e0d7a1678b.png)

# GridLayoutの列数を算出

GridLayoutの子の幅が揃っている場合は以下のやり方で子が収まるだけの列数を計算できる。

```yaml
ScrollView:
    GridLayout:
        size_hint: None, None
        size: self.minimum_size
        cols:
            max(self.parent.width - self.padding[0] - self.padding[2] + self.spacing[0]) // (self.spacing[0] + 子の幅)), 1)
```

長くて読みづらいがPython3.8を使っていれば代入式を使って以下のように読みやすくできる。

```yaml
ScrollView:
    GridLayout:
        size_hint: None, None
        size: self.minimum_size
        cols:
            (p := self.padding, s := self.spacing, ) and \\
            max(((self.parent.width - p[0] - p[2] + s[0]) // (s[0] + 子の幅)), 1)
```

またKivy2.0.0からはGridLayoutは縦方向を先に埋めることもできるので、その場合は以下のように行数を求められる。

```yaml
ScrollView:
    GridLayout:
        size_hint: None, None
        size: self.minimum_size
        orientation: 'tb-lr'  # 縦から埋める。tbはtop-to-bottom、lrはleft-to-rightの意。
        cols:
            (p := self.padding, s := self.spacing, ) and \\
            max(((self.parent.height - p[1] - p[3] + s[1]) // (s[1] + 子の高さ)), 1)
```

# 効率的な描画計算

pythonには[buffer protocol][buffer protocol]という物がある。これはデータがメモリ上で連続して並んでいるような物、つまりC-levelで以下のような単純なindexingでデータにアクセスできる物が従っているprotocolだったはずだ(私の記憶が正しければ)。

```C
float data[N];
for (i=0;i<N;i++){
    data[i] = ...
}
```

これに従っている物としてnumpy配列、[array][array]、[bytes][binary sequence]、[bytearray][binary sequence]等があるが、どうやらKivyにはこのような物を用いる事で描画過程に於ける無駄な一時データの生成を抑える仕組みがあるようなのである。それが以下の二つでだ。

## [Mesh][kivy_Mesh]

> Changed in version 1.8.1: Before, vertices and indices would always be converted to a list, now, they are only converted to a list if they do not implement the buffer interface. So e.g. numpy arrays, python arrays etc. are used in place, without creating any additional copies. However, the buffers cannot be readonly (even though they are not changed, due to a cython limitation) and must be contiguous in memory.

訳すと

> Kivy1.8.1より前は頂点データとindexデータは常にlistに変換されていたが、以降はそれらがbuffer interfaceを備えていない時のみ変換される。なのでnumpy配列や[array][array]は無駄な変換を生じさせずに使える。この時Kivy自体が中身を書き換えないにも関わらずそれらは読み取り専用であってはならないし、メモリ上で連続して並んでいなければならない。

のような感じになると思いますが、最後の「メモリ上で連続して並んでいなければならない」の意味は良く分からない。buffer protocolに従っている時点で連続して並んでいる事は保証されているのでは？もしかするとnumpyでいう

```python
numpy配列[真偽値の入ったnumpy配列]
```

のような要素の取捨選択をすると"必要な"要素は連続して並んでいないから駄目って言うことなのだろうか？この辺は実際に試してみる必要がありそうだ。

## [Texture][kivy_Texture]

> Since 1.9.0, you can blit data stored in a instance that implements the python buffer interface, or a memoryview thereof, such as numpy arrays, python array.array, a bytearray, or a cython array. This is beneficial if you expect to blit similar data, with perhaps a few changes in the data.

> When using a bytes representation of the data, for every change you have to regenerate the bytes instance, from perhaps a list, which is very inefficient. When using a buffer object, you can simply edit parts of the original data. Similarly, unless starting with a bytes object, converting to bytes requires a full copy, however, when using a buffer instance, no memory is copied, except to upload it to the GPU.

これも大体似たようなことを言っていて、要するに`Texture_blit_buffer()`にnumpy配列や[array][array]や[bytearray][binary sequence]を渡してやれば無駄な一時copyを作らずに済むよということらしい。

## まとめ

cythonを扱えない人でもnumpyを使って効率的な描画計算ができそうだと分かった。

[modules_official]:https://kivy.org/docs/api-kivy.modules.html
[modules_article]:http://qiita.com/gotta_dive_into_python/items/caa3e0f41ddfaedcdb95
[kviewer_official]:https://github.com/kivy/kivy/blob/master/kivy/tools/kviewer.py
[kviewer_article]:http://qiita.com/gotta_dive_into_python/items/c32cdcb58c66f0a1b840
[roberto_widgets_border]:http://robertour.com/2013/10/02/easy-way-debugging-kivy-interfaces/
[widget.py]:https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py
[widget.py.to_widget]:https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py#L846
[relativelayout.py]:https://github.com/kivy/kivy/blob/master/kivy/uix/relativelayout.py
[buffer protocol]:https://docs.python.org/ja/3/c-api/buffer.html
[array]:https://docs.python.org/ja/3/library/array.html
[binary sequence]:https://docs.python.org/ja/3/library/stdtypes.html#binary-sequence-types-bytes-bytearray-memoryview
[kivy_Mesh]:https://kivy.org/doc/master/api-kivy.graphics.html#kivy.graphics.Mesh
[kivy_Texture]:https://kivy.org/doc/master/api-kivy.graphics.texture.html#module-kivy.graphics.texture