在kivy中嵌套小部件

4
我正在尝试在kivy中创建一个界面,我认为我对自定义小部件以及它们的层次结构存在一些基本的不理解,甚至在完成教程后仍然如此。我认为我的思路更接近于盒子模型html,因此原生GUI中小部件的嵌套方式对我来说仍然有些陌生。
一些背景信息:
1.我查阅了this entry关于如何添加背景(它回答了问题:“如何在布局中添加背景图像/颜色/视频/...”,我相信我是通过_update_rect方法复制该课程)。
2.还有这个具有on_touch_down事件的。
好的,我想让MyApp看起来像这样...

enter image description here

据我了解,实现这个需要以下几步:
  1. 您需要一个应用程序。
  2. 该应用程序有一个根。
  3. 根具有背景,假设背景是白色的。
  4. 背景包含一个容器,假设该容器与背景有一点边距,并且是灰色的。我希望这是一个小部件而不仅仅是非小部件画布,因为我希望容器对点击事件做出反应。当被点击时,它会变成随机颜色(只是为了显示它正在执行某些操作)。
  5. 容器包含两个自定义小部件。这些是带标签的圆形,每个圆形都是绿色的。当被点击时,它们会变成随机颜色(只是为了显示它们正在执行某些操作)。

这是我的代码,它不再崩溃,但没有显示任何颜色或任何对象。

#!/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个回答

2
你的应用程序出现空白屏幕的原因是你的 build()方法没有返回任何内容。无论它返回什么,都将成为根小部件,但是即使您创建了一些小部件,也没有返回一个,因此什么也不会显示。
如果您解决了这个问题,可以再次运行该应用程序,但是您将立即收到一个错误,类似于 MyApp 没有属性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)

这很有帮助,但我不明白你所说的然而,这种方法试图修改MyApp.rect.pos...但是应用程序没有self.rect!你可能打算绑定到root._update_rect,而不是应用程序的方法。(编辑:我改为绑定到root._update_rect,现在至少红色背景和绿色圆圈出现了。) - Mittenchops
这对MyApp(应用程序)的def _update_rect(self, instance, value): self.rect.pos = instance.pos self.rect.size = instance.size 函数有什么影响?我应该将self.rect.pos更改为root,并将root作为该函数的输入传递吗? - Mittenchops
我已经编辑了一个更新的MyApp类,其中包含我想要的更改。它根本不需要_update_rect方法,因为该应用程序没有矩形。 - inclement

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接