web-dev-qa-db-ja.com

実行時にKivyでウィジェットの色を変更するにはどうすればよいですか?

Kivyでシンプルなウィジェットの色を変更するのに問題があります。ウィジェットの作成時に色を設定することはできますが、後で変更することはできません。

これが単純なレイアウト定義ファイルcircletest.kvです。これは、色(実際には、rgbaからのrのみ)、位置、およびサイズがすべてウィジェットクラスの変数にリンクされている円を定義します。

#:kivy 1.4.1

<CircleWidget>:
    canvas:
        Color:
            rgba: self.r,1,1,1
        Ellipse:
            pos: self.pos
            size: self.size

これがアプリケーションcircletest.pyです。シンプルなウィジェットを作成して表示します。オブジェクトの作成時に、色と位置が正常に設定されます。ウィジェットをクリックすると、ウィジェット自体の位置を変更できますが、色を変更しようとしても何も起こりません。

import kivy
kivy.require('1.4.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget

Builder.load_file('circletest.kv')

class CircleWidget(Widget):

    def __init__(s, **kwargs):
        s.size= [50,50]
        s.pos = [100,50]
        s.r = 0
        super(CircleWidget, s).__init__(**kwargs)

    def on_touch_down(s, touch):
        if s.collide_point(touch.x,touch.y):    
            s.pos = [s.pos[1],s.pos[0]]           # This works
            s.r = 1.0                       # <---- This does nothing!

class TestApp(App):

    def build(s):
        parent = Widget()
        w = CircleWidget()
        parent.add_widget(w)
        return parent

if __name__ == '__main__':
    TestApp().run()

誰かが問題を見ることができますか?

[〜#〜]更新[〜#〜]

この質問に対する答えが何であるかはまだわかりませんが、回避策があります。

.kvファイルで、オブジェクトの変数に色を指定しました。初期色を抽出するために動作します:

Color:
    rgba: self.col

.pyファイルから色を変更したい場合は、キャンバス内のすべての命令をループして、タイプ「Color」の最初の命令を変更します。明らかにこれはハックであり、複数のColor:プロパティを持つウィジェットでは機能しません。

for i in s.canvas.get_group(None):
    if type(i) is Color:
        i.r, i.g, i.b, i.a = v
        break

私はそれをすべてプロパティにまとめたので、使いやすくなっています。

class CircleWidget(Widget):

    def get_col(s):
        return s._col

    def set_col(s,v):
        for i in s.canvas.get_group(None):
            if type(i) is Color:
                i.r, i.g, i.b, i.a = v
                break
        s._col = v

    col = property(get_col, set_col)

    def __init__(s, **kwargs):
        s.size= [50,50]
        s.pos = [100,50]
        s._col = (1,1,0,1)
        super(CircleWidget, s).__init__(**kwargs)

    def on_touch_down(s, touch):
        if s.collide_point(touch.x,touch.y):    
            s.col = (s.col[::-1]) # Set to some other color

今のところうまくいくようです。これを行うためのより良い方法を知っている場合は、私に知らせてください。もっと簡単な方法があるに違いない、そして私は明白な何かを見逃していると確信しています!

18
Andy

最初のバージョンでは、プロパティの宣言が欠落していました

_from kivy.properties import NumericProperty
_

ヘッダーと

_r = NumericProperty(0)
_

class CircleWidget(Widget):のすぐ下

また、kvファイルの名前はcircletest.kvであるが、アプリの名前はTestAppであると述べているため、一貫性を持たせるためにいずれかを変更する必要があります。そうしないと、kvファイルが見つかりませんが、報告しないためです。それに関する問題は、私はそれが問題のタイプミスにすぎないと思います。編集:_Builder.load_file_わかりました、

乾杯。

14
Tshirtman

Tshirtmanの答えは正解です。これが何が起こっているのかについての説明です。

あなたが設定したときにあなたのkvファイルで

<CircleWidget>:
    canvas:
        Color:
            rgba: self.r, 1, 1, 1
        Ellipse:
            pos: self.pos
            size: self.size

この線 rgba: self.r, 1, 1, 1rgbaの値に変更があるたびに、rの値を更新しようとします。これは、バインディングによってkv言語で暗黙的に実行されます。これは、 Observer Pattern を実装するため、 kivy Property で実行できます。

コード内の変数rは更新されましたが、値が変更されてバインドできないことを示すものではない単なる変数です。 pos はReferenceListPropertyであるため、posへの変更が機能することに気付いた場合。

Kivyでのプログラミングの一般的なルール。ウィジェット/オブジェクトのプロパティに応じてコードを変更する場合は、 Kivyプロパティ を使用します。 プロパティの変更を監視 するオプションを提供し、それに応じてコードを bind / on_property_name イベントを介して明示的に調整するか、上記のようにkv言語を介して暗黙的に調整します。 。

17
qua-non