2

でカスタム ウィジェットを使用しようとしていますGridLayoutが、ウィンドウ全体にグリッドが拡大するのではなく、常に隅に非常に小さなグリッドが表示されます。

サンプルコード:

import kivy
kivy.require('1.5.1')

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout



class MyWidget(Widget):
    def __init__(self):
        super(MyWidget, self).__init__()

        grid_layout = GridLayout(cols=3)
        grid_layout.add_widget(Button(text='A'))
        grid_layout.add_widget(Button(text='B'))
        grid_layout.add_widget(Label(text='text'))
        grid_layout.add_widget(Label(text='other'))
        grid_layout.add_widget(Button(text='text'))
        self.add_widget(grid_layout)


class MyApp(App):
    def build(self):
        float = 
        return MyWidget()


MyApp().run()

Widgetのデフォルトsize_hint(1,1)、ウィンドウ全体に展開する必要があるためですGridLayout。なぜこれが起こらないのですか?どうすれば望む結果を得ることができますか?

4

2 に答える 2

5
`class MyWidget(Widget):`

ルート ウィジェットは、レイアウトMyWidgetの 1 つからではなく から継承するためWidget、その子のサイズを制御しません。

ルート ウィジェットは、ウィンドウのスペース全体を占有します。MyWidget次のようなキャンバスに Rectangle を追加することで、これをテストできます::

with self.canvas.before:
    Color(1,0,0,1)
    Rectangle(pos=self.pos, size=self.size)

canvas、canvas.before、および canvas.afterに慣れる必要があります。これらは基本的に命令のグループであり、before グループはウィジェットのキャンバス命令の前に描画され、after グループは after に描画されます。

ただし、Kivy で異なる重要な点の 1 つは、ウィジェットのサイズ変更/レイアウトが次のフレームまで遅延されることです。そのため、上記のスニペットを次のようにコードに追加すると::

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import *


class MyWidget(Widget):

    def __init__(self, **kwargs):
        # I'd make sure to pass of kwargs through to the super
        # as there are widgets's that process their initial
        # arguments through.
        super(MyWidget, self).__init__(**kwargs)

        grid_layout = GridLayout(cols=3)
        grid_layout.add_widget(Button(text='A'))
        grid_layout.add_widget(Button(text='B'))
        grid_layout.add_widget(Label(text='text'))
        grid_layout.add_widget(Label(text='other'))
        grid_layout.add_widget(Button(text='text'))
        self.add_widget(grid_layout)
        with self.canvas.before:
            Color(1,0,0,1)
            Rectangle(pos=self.pos, size=self.size)


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

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

これは、ウィジェットの初期位置とサイズでのみ赤い四角形を表示します。その時点では、デフォルトの位置とサイズはそれぞれ (0, 0) と (100, 100) です。

赤い四角形をウィジェットのサイズに合わせるには、次のようにサイズをウィジェットのサイズにバインドする必要があります::

...
        grid_layout.add_widget(Button(text='text'))
        self.add_widget(grid_layout)
        with self.canvas.before:
            Color(1,0,0,1)
            self.rect = Rectangle(pos=self.pos, size=self.size)
        self.bind(size=self.update_rect)

    def update_rect(self, instance, value):
        self.rect.pos = self.pos
        self.rect.size = self.size

class MyApp(App):
    def build(self):
...

上記のコードの出力が示すように、ウィジェットはウィンドウ全体のサイズを占めています。ただし、これで問題は解決せず、子レイアウトは元の位置と元のサイズのままです。これは、上記のように、ウィジェットが子のサイズを制御しないためです。

rect を更新するようにウィジェットの子/子のサイズと位置を更新するか (複数の子があるとすぐに複雑になります)、レイアウトの 1 つをルート ウィジェットとして使用します。

これは、次のように kv で行うこともできます::

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder

Builder.load_string('''
# this is the rule for MyWidget that defines
# what MyWidget looks like i.e.drawing
# instructions and widgets etc 
<MyWidget>:
    canvas.before:
        Color:
            rgba: 1, 0, 0, 1
        Rectangle:
            # this implicitly binds the size of the
            # rect to the size of the widget
            size: self.size
            # self here still refers to the widget as Rectangle is only a
            # graphics instruction and not a widget
            pos: self.pos
    GridLayout:
        cols: 3
        # root here refers to the `MyWidget`, bind the size of the
        # GridLayout to the size of your root widget
        size: root.size
        Button:
            text: 'A'
        Button:
            text: 'B'
        Label:
            text: 'text'
        Label:
            text: 'other'
        Button:
            text: 'text'        
''')


class MyWidget(Widget):
    pass


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

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

上記の例では、子のサイズをその親ウィジェットのサイズにバインドします。レイアウトをルート ウィジェットとして使用することを引き続きお勧めします。レイアウトをネストすることをためらわないでください。

于 2012-12-25T20:17:40.723 に答える
0

メイン クラスを Widget ではなく GridLayout から継承するソリューションを好みます。実際、これは振り返ってみると非常に明白なように思えるので、チュートリアルでウィジェット アプローチを使用する理由がまったくわからないのです。前の回答ではこの手法を推奨していましたが、コードを提供すると思いました。

import kivy
kivy.require('1.5.1')

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout

class MyWidget(GridLayout):
    def __init__(self):
        super(MyWidget, self).__init__(cols=3)

        self.add_widget(Button(text='A'))
        self.add_widget(Button(text='B'))
        self.add_widget(Label(text='text'))
        self.add_widget(Label(text='other'))
        self.add_widget(Button(text='text'))

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


MyApp().run()

またはkvlangを使用:

import kivy
kivy.require('1.5.1')

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder

Builder.load_string('''
<MyWidget>:
    cols:3
    Button:
        text:'A'
    Button:
        text:'B'
    Label:
        text:'text'
    Label:
        text:'other'
    Button:
        text:'text'
''')

class MyWidget(GridLayout):
    pass
class MyApp(App):
    def build(self):
        return MyWidget()

if __name__ == "__main__":
    MyApp().run()
于 2015-10-21T08:31:52.603 に答える