2016-07-29 32 views
9

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

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() 

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

SimpleBarの「hi」ラベルの前に、NewBarの「2」ラベルを配置します。

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

私は知っている - アイテムを否定することができます。しかし、<-NewBar>はすべての私のスタイリングを削除します。

kivy言語でこれを行う方法はありますか?シンプルKVで

+0

少し編集を加えて、今でも象徴をサポートしています^^ – KeyWeeUsr

答えて

2

いいえ、何が既にした後、既定の場所でウィジェットを使用すると、ウィジェット(例えばLabel: ...)で何かを置けば、それは<widget>.add_widget()メソッドを呼び出しますし、そのような方法がadditionalパラメータなしで呼び出されたときに、それがするのではそれの前に置かれる。したがってkivy/lang/parser.pyファイルを検索し、そのような機能(PR歓迎)を追加するか、またはhm ... __init__のPython内で実行するか、ウィジェットを追加したい(多分何らかのイベントの後に)ことができます。

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

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 
<[email protected]>: 

<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() 
2

はここで楽しいことだ:あなたはLANG自体にKV 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() 

これを使用して、後でさまざまなコンテンツを埋め込むテンプレートベースウィジェットを作成しましょう。私たちは、この基本テンプレートクラスの__init__方法でプレースホルダのクラスを登録するPythonコードで

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

:私たちは、後で別のウィジェットに置き換えるプレースホルダを使用しています。

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() 
2

あなたは、複合ウィジェットをしたい場合は、それは新しい子供を受け入れて、ある特定の「コンテナ」ウィジェットでそれらを追加するには、あなたは、いくつかのpythonを行う必要があります。

基本的には、add_widgetをオーバーライドして、そのウィジェットの基本構造がそこにあれば、新しいウィジェットが新しいメソッドを使用して追加されるようにします。

は、あなたがこのルール

<NestingWidget>: 
    Label: 
     text: root.title 

    BoxLayout: 

    Button: 
     on_press: root.activate() 

このNestingWidget

class NestingWidget(BoxLayout): 
    title = StringProperty() 

    def activate(self): 
     # do something 
     pass 

を持っていて、このようにそれを使用したいとしましょう:これはすぐに動作しません

FloatLayout: 
    NestingWidget: 
     title: 'first item' 
     Image: 
      source: '../examples/demo/pictures/images/Ill1.jpg' 

Imageがの直接の子として追加されるためです10、それはButtonの下にあるでしょう。

kivyのウィジェットの中には、既にネストされた新しいウィジェットを受け入れることができますが、すでに複雑なものになっている可能性があります。

これを行うには、前にも述べたように、add_widgetを上書きするしかありません。

まず、IDをコンテナに追加しましょう。

<NestingWidget>: 
    Label: 
     text: root.title 

    BoxLayout: 
     id: container 

    Button: 
     on_press: root.activate() 

そして、のはadd_widgetでそれを使ってみましょう。

class NestingWidget(BoxLayout): 
    … 
    def add_widget(self, *args, **kwargs): 
     if 'container' in self.ids: 
      return self.ids.container.add_widget(*args, **kwargs) 
     else: 
      return super(NestingWidget, self).add_widget(*args, **kwargs) 
関連する問題