将小部件嵌套在kivy中

时间:2013-12-04 04:21:45

标签: python user-interface widget kivy

我正在尝试在kivy中创建一个界面,我认为有些基本的东西我不了解自定义小部件以及如何对它们进行分层,即使在完成教程之后也是如此。我认为我有更多的盒子模型html心态,所以窗口小部件嵌套在原生GUI中的方式对我来说仍然是一种陌生的。

一些背景知识:

  1. 我咨询this entry如何添加背景(它回答了问题:“如何将背景图像/颜色/视频/ ...添加到布局中”,我相信我是用_update_rect方法复制。)

  2. This one有on_touch_down事件。

  3. K,我正试图让MyApp看起来像这样......

    enter image description here

    据我了解,以下是我需要的东西:

    1. 你有一个应用程序。
    2. 该应用有根。
    3. 根有背景,背景是白色。
    4. 背景包含一个支架,说支架与背景有一点距离并且是灰色的。我确实希望这是一个小部件,而不仅仅是一个非小部件画布,因为我希望持有者对点击事件做出反应。单击时会变成随机颜色。 (只是为了表明它正在做某事。)
    5. 持有者包含两个自定义小部件。这些是带有标签的圆圈,每个都是绿色。点击时它们会变成随机颜色(只是为了表明它们正在做某事)。
    6. 这是我的代码,它不会再崩溃,但不会显示任何颜色或任何类型的对象。

      #!/usr/bin/kivy
      import kivy
      kivy.require('1.7.2')
      
      from random import random
      from kivy.app import App
      from kivy.uix.widget import Widget
      from kivy.uix.floatlayout import FloatLayout
      from kivy.graphics import Color, Ellipse, Rectangle
      
      class MyApp(App):
          title = 'My App'
          def build(self):
              root = RootWidget()
              root.bind(
                  size=self._update_rect,
                  pos=self._update_rect)
          def _update_rect(self, instance, value):
              self.rect.pos = instance.pos
              self.rect.size = instance.size
      
      class RootWidget(FloatLayout):
          def __init__(self, **kwargs):
              super(RootWidget, self).__init__(**kwargs)
              with self.canvas.before:
                  Color(1, 0, 0, 1) # This RED does not display.
                  self.rect = Rectangle(
                                          size=self.size,
                                          pos=self.pos,
                                          text="some junk!")  # This label does not display.
              mybackground = Background()
              self.add_widget(mybackground)
          def _update_rect(self, instance, value):
              self.rect.pos = instance.pos
              self.rect.size = instance.size
      
      class Background(Widget):
          def __init__(self, **kwargs):
              super(Background, self).__init__(**kwargs)
              with self.canvas.before:    
                  Color(1, 1, 1, 1)       # This WHITE does not display
                  self.rect = Rectangle(
                                          size=self.size,
                                          pos=self.pos,
                                          text="More stuff!")  # This label does not display.
              myholder = Holder()
              self.add_widget(myholder)
          def _update_rect(self, instance, value):
              self.rect.pos = instance.pos
              self.rect.size = instance.size
      
      class Holder(Widget):
          def __init__(self, **kwargs):
              super(Holder, self).__init__(**kwargs)
              with self.canvas.before:    
                  Color(0.25, 0.25, 0.25, 1) # This GRAY does not display
                  self.rect = Rectangle(
                                          size=self.size,
                                          pos=self.pos,
                                          text="More stuff!")  # This does not display.
              c1 = Circley(label="Label 1")  # I see I'd need to do some size/pos math here to center
              c2 = Circley(label="Label 2")  # but since everything isn't working, I've tabled this.
              self.add_widget(c1)
              self.add_widget(c2)
          def _update_rect(self, instance, value):
              self.rect.pos = instance.pos
              self.rect.size = instance.size
          def on_touch_down(self, touch):
              rcolor = Color(random(), random(), random(), 1)
              with self.canvas:
                  self.color = rcolor
      
      class Circley(Widget):
          def __init__(self, label='label', **kwargs):
              super(Circley, self).__init__(**kwargs)
              with self.canvas.before:    
                  Color(0, 1, 0, 1) # This GREEN does not display
                  self.circ = Ellipse(
                              size=self.size,
                              pos=self.pos,
                              text=label
                  )
          def _update_circ(self, instance, value):
              self.circ.pos = instance.pos
              self.circ.size = instance.size
          def on_touch_down(self, touch):
              rcolor = Color(random(), random(), random(), 1)
              with self.canvas:
                  self.color = rcolor
      
      if __name__ == '__main__':
          MyApp().run()
      

      关于我做错了什么以及如何正确嵌套这些小部件的任何指示?

2 个答案:

答案 0 :(得分:2)

您获得空白屏幕的原因是您的应用的build()方法不会返回任何内容。无论它返回什么都是根小部件,但即使你制作了一些小部件,也不会返回一个小部件,因此不会显示任何内容。

如果你解决了这个问题,你可以再次运行该应用,但是你会立即收到MyApp has no attribute rect之类的错误。这是因为您的根窗口小部件会立即调整大小并定位以填充窗口,该窗口(根据您的root.bind行)触发MyApp._update_rect。但是,此方法尝试修改MyApp.rect.pos ...但该应用程序没有self.rect!您可能打算绑定到root._update_rect,而不是应用程序的方法。 (编辑:我绑定到root._update_rect,现在至少出现红色背景和绿色圆圈。)

编辑:作为旁注,使用kv语言会更容易,这可以自动处理很多小部件创建,矩形绑定等。

我现在没时间修复它,但也许这两个问题可以帮助您修复整体流程。如果没有其他人的话,我会稍后发布一个更完整的答案。


根据评论,这是一个更新的MyApp。

class MyApp(App):
    title = 'My App'
    def build(self):
        root = RootWidget()
        root.bind(
            size=root._update_rect,
            pos=root._update_rect)

答案 1 :(得分:0)

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import Color, Rectangle, Ellipse


class MyApp(App):
    title = 'My App'
    def build(self):
        root = RootWidget()
        root.bind(
            size=root._update_rect,
            pos=root._update_rect)
        return root

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Color(1, 0, 0, 1) # This RED does not display.
            self.rect = Rectangle(
                                    size=self.size,
                                    pos=self.pos,
                                    text="some junk!")  # This label does not display.
        mybackground = Background()
        self.add_widget(mybackground)
    def _update_rect(self, instance, value):
        self.rect.pos = instance.pos
        self.rect.size = instance.size

class Background(Widget):
    def __init__(self, **kwargs):
        super(Background, self).__init__(**kwargs)
        with self.canvas.before:    
            Color(1, 1, 1, 1)       # This WHITE does not display
            self.rect = Rectangle(
                                    size=self.size,
                                    pos=self.pos,
                                    text="More stuff!")  # This label does not display.
        myholder = Holder()
        self.add_widget(myholder)
    def _update_rect(self, instance, value):
        self.rect.pos = instance.pos
        self.rect.size = instance.size

class Holder(Widget):
    def __init__(self, **kwargs):
        super(Holder, self).__init__(**kwargs)
        with self.canvas.before:    
            Color(0.25, 0.25, 0.25, 1) # This GRAY does not display
            self.rect = Rectangle(
                                    size=self.size,
                                    pos=self.pos,
                                    text="More stuff!")  # This does not display.
        c1 = Circley(label="Label 1")  # I see I'd need to do some size/pos math here to center
        c2 = Circley(label="Label 2")  # but since everything isn't working, I've tabled this.
        self.add_widget(c1)
        self.add_widget(c2)
    def _update_rect(self, instance, value):
        self.rect.pos = instance.pos
        self.rect.size = instance.size
    def on_touch_down(self, touch):
        rcolor = Color(random(), random(), random(), 1)
        with self.canvas:
            self.color = rcolor

class Circley(Widget):
    def __init__(self, label='label', **kwargs):
        super(Circley, self).__init__(**kwargs)
        with self.canvas.before:    
            Color(0, 1, 0, 1) # This GREEN does not display
            self.circ = Ellipse(
                        size=self.size,
                        pos=self.pos,
                        text=label
            )
    def _update_circ(self, instance, value):
        self.circ.pos = instance.pos
        self.circ.size = instance.size
    def on_touch_down(self, touch):
        rcolor = Color(random(), random(), random(), 1)
        with self.canvas:
            self.color = rcolor

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