21

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:プロパティを持つウィジェットでは機能しません。

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

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

4

2 に答える 2

18

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

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

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

この行は、の値が変更されるたびに rgba: self.r, 1, 1, 1の値を更新しようとします。これは、バインディングによってkv言語で暗黙的に実行されます。これは、オブザーバーパターンを実装するkivyプロパティで実行できます。rgbar

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

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

于 2012-10-22T10:58:48.067 に答える
16

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

from kivy.properties import NumericProperty

ヘッダーと

r = NumericProperty(0)

すぐ下にclass CircleWidget(Widget):

また、kvファイルの名前はcircletest.kvであると述べていますが、アプリの名前はTestAppであるため、コヒーレントにするためにいずれかを変更する必要があります。そうしないと、kvファイルが見つかりませんが、報告しないためです。それに関する問題は、私はそれが問題のタイプミスにすぎないと思います。編集:Builder.load_file大丈夫を見た、

乾杯。

于 2012-10-22T09:19:59.843 に答える