9

Kivy 言語は継承されたレイアウトとウィジェットにアクセスできますか? ウィジェットのスタイリングとタイトル ラベルを含む基本的な BoxLayout を 1 つ作成したいと考えています。このウィジェットから継承し、別の位置にウィジェットを追加できるようにしたいと考えています。

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

Builder.load_string('''
<SimpleBar>:
    canvas.before:
        Color:
            rgba: 0, 0.5, 0.5, 1
        Rectangle:
            pos: self.pos
            size: self.size
    BoxLayout:
        id: my_layout
        Label:
            text: "hi"

<NewBar>:
    Label:
        text: "2"
''')

class SimpleBar(BoxLayout):
    def log(self, value):
        print(value)

class NewBar(SimpleBar):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print(dir(self))

class GeneralApp(App):
    def build(self):
        return NewBar()

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

上記は私の基本的な実行中のウィジェットです。

以下のように、NewBar の "2" ラベルを SimpleBar の 'hi' ラベルの前に配置したいと考えています。

<NewBar>:
     BoxLayout:
         id: my_layout
         Label:
             text: "2"
         Label:
             text: "hi"

私はそれを知っています-アイテムを無効にすることができます。ただし、<-NewBar>私のスタイリングはすべて削除されます。

これをkivy言語で行う方法はありますか?

4

3 に答える 3

5

ここに面白いことがあります: kv lang で使用されるすべてのクラスを lang 自体で指定する必要はありませんFactory.register。コードの後半でメソッドを使用してそれらを追加することもできます。次に例を示します。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.factory import Factory

from functools import partial

Builder.load_string('''

<MyWidget>:
    Foo
    Bar
''')

class MyWidget(BoxLayout):
    pass

class MyApp(App):
    def build(self):
        Factory.register('Foo', cls=partial(Label, text='foo'))
        Factory.register('Bar', cls=partial(Label, text='bar'))
        return MyWidget()

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

これを使用して、後でさまざまなコンテンツを入力するテンプレート ベース ウィジェットを作成しましょう。後で別のウィジェットに置き換えるプレースホルダーを使用します。

<BaseWidget>:
    orientation: 'vertical'
    Label:
        size_hint: None, 0.1
        text: 'title'
    Placeholder

Python コードでは__init__、この基本テンプレート クラスのメソッドにプレースホルダー クラスを登録します。

class BaseWidget(BoxLayout):
    def __init__(self, **args):
        # unregister if already registered...
        Factory.unregister('Placeholder')
        Factory.register('Placeholder', cls=self.placeholder)
        super(BaseWidget, self).__init__(**args)

それでは、コンテンツ クラスを定義しましょう。

<TwoButtonWidget>:
    Button:
        text: 'button 1'
    Button:
        text: 'button 2'

最後に、基本クラスをテンプレートとして使用し、そのプレースホルダーをコンテンツ クラスに置き換えるカスタマイズされたクラスを作成します。このクラスには独自の kivy ルールがないため (これらはコンテンツ クラスに移動されます)、基本テンプレートから継承する場合、追加のウィジェットは挿入されません。

# content class
class TwoButtonWidget(BoxLayout):
    pass

# Base class subclass
class CustomizedWidget(BaseWidget):
    placeholder = TwoButtonWidget # set contetnt class

完全な例:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.factory import Factory

Builder.load_string('''
<BaseWidget>:
    orientation: 'vertical'
    widget_title: widget_title
    placeholder: placeholder
    Label:
        size_hint: None, 0.1
        id: widget_title
    Placeholder
        id: placeholder

<TwoButtonWidget>:
    button1: button1
    Button:
        text: 'button 1'
        id: button1
    Button:
        text: 'button 2'

<ThreeButtonWidget>:
    orientation: 'vertical'
    Button:
        text: 'button a'
    Button:
        text: 'button b'
    Button:
        text: 'button c'
''')

class BaseWidget(BoxLayout):
    def __init__(self, **args):
        # unregister if already registered...
        Factory.unregister('Placeholder')
        Factory.register('Placeholder', cls=self.placeholder)
        super(BaseWidget, self).__init__(**args)

class TwoButtonWidget(BoxLayout):
    pass

class ThreeButtonWidget(BoxLayout):
    pass

class CustomizedWidget1(BaseWidget):
    placeholder = TwoButtonWidget

class CustomizedWidget2(BaseWidget):
    placeholder = ThreeButtonWidget

class MyApp(App):
    def build(self):
        layout = BoxLayout()
        c1 = CustomizedWidget1()
        # we can access base widget...
        c1.widget_title.text = 'First'
        # we can access placeholder
        c1.placeholder.button1.text = 'This was 1 before'

        c2 = CustomizedWidget2()
        c2.widget_title.text = 'Second'

        layout.add_widget(c1)
        layout.add_widget(c2)
        return layout

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

簡単に拡張でき、たとえば、複数のプレースホルダーを持つことができます。

これをあなたのケースに適用します:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.factory import Factory

from functools import partial

Builder.load_string('''

<SimpleBar>:
    canvas.before:
        Color:
            rgba: 0, 0.5, 0.5, 1
        Rectangle:
            pos: self.pos
            size: self.size
    BoxLayout:
        Placeholder
        Label:
            text: "hi"

<NewBarContent>:
    Label:
        text: "2"
''')

class SimpleBar(BoxLayout):
    def __init__(self, **args):
        # unregister if already registered...
        Factory.unregister('Placeholder')
        Factory.register('Placeholder', cls=self.placeholder)
        super(SimpleBar, self).__init__(**args)

class NewBarContent(BoxLayout):
    pass

class NewBar(SimpleBar):
    placeholder = NewBarContent

class MyApp(App):
    def build(self):
        return NewBar()

if __name__ == '__main__':
    MyApp().run()
于 2016-08-28T21:52:16.110 に答える
2

単純な kv no では、ウィジェットに何かを配置すると (例: Label: ...)、<widget>.add_widget()メソッドが呼び出され、そのようなメソッドが追加のパラメーターなしで呼び出されると、デフォルトでウィジェットがその前に既に配置されているものの後に配置されるためです。したがって、ファイルを検索してそのkivy/lang/parser.pyような機能を追加するか (PR 歓迎)、または python in hm...__init__またはウィジェットを追加したい場所 (おそらく何らかのイベントの後) で実行できます。

<widget (or self)>.add_widget(<child>, index=<where>)Python内でそれを行うには、ドキュメントに従って呼び出すことができます。例えば:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty

Builder.load_string('''
#:import Factory kivy.factory.Factory
<Ninja@Label>:

<SimpleBar>:
    BoxLayout:
        id: my_layout
        Label:
            text: "hi"

<ChildWithBenefits>:
    placebefore:
        [(Factory.Label(text='I am the first!'), 0),
        (Factory.Ninja(text='No, I am!'), 2)]
''')

class SimpleBar(BoxLayout):
    def log(self, value):
        print(value)

class ChildWithBenefits(SimpleBar):
    placebefore = ListProperty([])
    def __init__(self, *args, **kwargs):
        super(ChildWithBenefits, self).__init__(*args, **kwargs)
        for child, index in self.placebefore:
            print child.text
            print type(child)
            self.add_widget(child, index=index)
        self.log('Hello!')

class GeneralApp(App):
    def build(self):
        return ChildWithBenefits()

if __name__ == '__main__':
    GeneralApp().run()
于 2016-08-27T15:56:11.503 に答える