如何引用看似超出范围的小部件 - 改编为kivy / examples / demo / images

时间:2014-10-15 03:51:13

标签: python class reference kivy

我编辑了kivy / examples / demo / images文件以尝试执行以下操作: - 对于每个添加的图像,它还在侧栏中添加一个按钮(不同的boxlayout) - 单击按钮时,它会删除图像和按钮

为了做到这一点,我创建了(这是一个简短的摘要代码,可以给你一个想法)

boxlayout:
    floatlayout:
    #this is where the images, in their own class called "Picture" just like in the demo get added
    boxlayout:
    #this is where the buttons get added. I created a class for them called "PictureBtn"

创建图片时,我会为其添加唯一ID。 然后我创建PictureBtn并添加相同的ID。 然后我在各自的位置填充图片和按钮。一切都很好。

现在的问题是,从Pictures和PictureBtn实例,我可以引用应用程序,但我不知道如何引用其他实例。身份证似乎不在任何地方。

我理解它的方式是因为它们超出了范围。 id只能在本地保存,因为PictureBtn和Pictures都有自己的root,我无法找到它们。

我的完整代码如下:

    import kivy
kivy.require('1.0.6')

from glob import glob
from random import randint
from os.path import join, dirname
from kivy.app import App
from kivy.logger import Logger
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
# FIXME this shouldn't be necessary
from kivy.core.window import Window

#declare global var for keeping track of unique ids
number_of_pics=0


class Picture(Scatter):
    '''Picture is the class that will show the image with a white border and a
    shadow. They are nothing here because almost everything is inside the
    picture.kv. Check the rule named <Picture> inside the file, and you'll see
    how the Picture() is really constructed and used.

    The source property will be the filename to show.
    '''

    source = StringProperty(None)


class PictureBtn(BoxLayout):
    pass

class PicturesApp(App):

    def build(self):
        global number_of_pics

        # the root is created in pictures.kv
        root = self.root

        # get any files into images directory
        curdir = dirname(__file__)
        for filename in glob(join(curdir, 'images', '*')):
            try:
                # load the image
                picture = Picture(source=filename, rotation=randint(-30,30))
                picture.id='pic'+str(number_of_pics)

                button = PictureBtn()
                button.id = 'pic'+str(number_of_pics)
                button.ids.lbl.text= button.id

                # add to the main field
                self.root.ids.picspace.add_widget(picture)
                self.root.ids.sidebar.add_widget(button)

                number_of_pics+=1                
            except Exception as e:
                Logger.exception('Pictures: Unable to load <%s>' % filename)

    def on_pause(self):
        return True

    def RemovePicture(self,byid):
        #my attempt (obviously failing) at removing the Picture instance and the
        #PictureBtn instance with the id "byid"
        self.root.ids.sidebar.remove_widget(self.root.ids.sidebar.ids.byid)
        self.root.ids.picspace.remove_widget(self.root.ids.picspace.ids.byid)

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

然后我的kv文件包含以下内容:

#:kivy 1.0
#:import kivy kivy
#:import win kivy.core.window

BoxLayout:
    orientation: 'horizontal'
    FloatLayout:
        id: picspace
        size_hint: 0.8,1
        canvas:
            Color:
                rgb: 1, 1, 1
            Rectangle:
                source: 'data/images/background.jpg'
                size: self.size

        BoxLayout:
            padding: 10
            spacing: 10
            size_hint: 1, None
            pos_hint: {'top': 1}
            height: 44
            Image:
                size_hint: None, None
                size: 24, 24
                source: 'data/logo/kivy-icon-24.png'
            Label:
                height: 24
                text_size: self.width, None
                color: (1, 1, 1, .8)
                text: 'Kivy %s - Pictures' % kivy.__version__
    BoxLayout:
        id: sidebar
        orientation: 'vertical'


<Picture>:
    # each time a picture is created, the image can delay the loading
    # as soon as the image is loaded, ensure that the center is changed
    # to the center of the screen.
    on_size: self.center = win.Window.center
    size: image.size
    size_hint: None, None

    Image:
        id: image
        source: root.source

        # create initial image to be 400 pixels width
        size: 400, 400 / self.image_ratio

        # add shadow background
        canvas.before:
            Color:
                rgba: 1,1,1,1
            BorderImage:
                source: 'shadow32.png'
                border: (36,36,36,36)
                size:(self.width+72, self.height+72)
                pos: (-36,-36)

<PictureBtn>:
    orientation: 'horizontal'
    Label:
        id: lbl
        text: ''
    Button:
        text: 'X'
        on_release: app.RemovePicture(self.parent.id)

(我的原始代码是类似的情况,但我在其中一个kivy / examples中创建了同样的问题,试图让它更容易解决。)

由于

2 个答案:

答案 0 :(得分:0)

好的,我终于找到了办法,但我确信必须有更好的方法:

def RemovePicture(self,idee):
    for child in self.ids.picspace.children:
        if child.id==idee:
            self.ids.picspace.remove_widget(child)   
    for child in self.ids.sidebar.children:
        if child.id==idee:
            self.ids.sidebar.remove_widget(child)   

所以这似乎有效。它们不会显示在ID列表中,但它们会显示在子列表中。我仍然不确定为什么会这样。如果有人知道更好/更合适的方式,请告诉我。

答案 1 :(得分:0)

id仅在kv中有效,并且与根规则相关。它们不是应用程序范围的全局标识符,用于引用您的小部件。以下是一个简单的例子:

<MyWidget@BoxLayout>:
    Label:
        id: mylabel
    Button:
        id: mybutton

BoxLayout:
    MyWidget:
        id: widget1
    MyWidget:
        id: widget2

在此示例中,id mylabel引用哪个小部件? widget1中的实例或widget2中的实例?

因此,您可以遍历子项以查找和删除小部件,也可以将自己的引用存储在dict中。例如,在_pictures类上创建PicturesApp dict,然后在添加图片时:

# add to the main field
self._pictures[number_of_pics] = (picture, button)
self.root.ids.picspace.add_widget(picture)
self.root.ids.sidebar.add_widget(button)

您的删除代码将变为:

def remove_picture(self, idee):
    picture, button = self._pictures.pop(idee)
    picture.parent.remove_widget(picture)
    button.parent.remove_widget(button)