简体   繁体   中英

How to add widgets to a list if it's possible in kivy/python?

So what I want to do is to add a bunch of widgets to a list and later on, be able to draw each widget on the canvas. I am thinking of using a loop (for example, for widget in widgets: ) and then calling their draw functions. I want each widget to be it's own entity, as in they don't depend on each other (as in if I choose to delete one, the others won't be deleted as well). So far, I have the code for the bare minimum (it only draws 1 yellow dot):

from kivy.app import App

from kivy.uix.widget import Widget

from kivy.graphics import Color, Ellipse, Line

class YellowDot(Widget):

    def draw(self):
        with self.canvas:
            Color(1,1,0)
            Ellipse(pos=(500, 500), size=(50,50))

class TestApp(App):

    def build(self):
        game=YellowDot()
        game.draw()
        return game

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

I know this is possible in regular python for objects, as in you can add objects to a list and call their respective functions. Is it possible to add widgets in a list or something similar?

There are two ways and which to choose depends on if you want the widgets to be able to be garbage-collected (free from memory) or not:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.weakproxy import WeakProxy
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Ellipse, Line
from random import randint as r

class Dot(Widget):

    def __init__(self, dot_color=None, **kwargs):
        super(Dot, self).__init__(**kwargs)

        if not dot_color:
            raise Exception('No color available!')
        self.dot_color = dot_color

        # call draw automatically
        self.draw()

    def draw(self):
        with self.canvas:
            Color(*self.dot_color)
            Ellipse(pos=self.pos, size=self.size)

class TestApp(App):

    def build(self):
        colors = ((1, 0, 0),
                  (0, 1, 0),
                  (0, 0, 1))

        do_weak_referencing = False  # change to True for weakrefs
        if do_weak_referencing:
            # get the class for weak referencing
            # variant 1
            wp = WeakProxy
            self.dots = [
                WeakProxy(
                    Dot(dot_color=dc,
                        pos=(r(100, 500), r(100, 500)))
                ) for dc in colors]
        else:
            # variant 2
            self.dots = [
                Dot(dot_color=dc,
                    pos=(r(100, 500), r(100, 500))
                ) for dc in colors]

        box = BoxLayout()
        for dot in self.dots:
            # where will our dot be?
            print(dot.pos)
            box.add_widget(dot)

        # what the list look like?
        print(self.dots)
        return box

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

Note that if the object is in a list as a WeakProxy and is not added anywhere (as a child), it'll be collected and if you try to access it later, it'll raise an error that it's not available (obviously) - variant 1.

However if you choose to go straight for the strong reference, the object won't be collected unless popped out from the self.dots list.

I put self.draw() directly in __init__ , so that you could see where the dots are, but you can remove it and call it directly from App.dots eg:

app = App.get_running_app()
app.dots[0].draw()
# tada!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM