首页 > 解决方案 > Why is 'root' keyword treated differently when it is called in Kivy?

问题描述

How to make circular progress bar in kivy?

I have found a source above for circular progress bar and noted something weird.

from kivy.app import App
from kivy.uix.progressbar import ProgressBar
from kivy.core.text import Label as CoreLabel
from kivy.lang.builder import Builder
from kivy.graphics import Color, Ellipse, Rectangle
from kivy.clock import Clock


class CircularProgressBar(ProgressBar):

    def __init__(self, **kwargs):
        super(CircularProgressBar, self).__init__(**kwargs)

        # Set constant for the bar thickness
        self.thickness = 40

        # Create a direct text representation
        self.label = CoreLabel(text="0%", font_size=self.thickness)

        # Initialise the texture_size variable
        self.texture_size = None

        # Refresh the text
        self.refresh_text()

        # Redraw on innit
        self.draw()

    def draw(self):

        with self.canvas:

            # Empty canvas instructions
            self.canvas.clear()

            # Draw no-progress circle
            Color(0.26, 0.26, 0.26)
            Ellipse(pos=self.pos, size=self.size)

            # Draw progress circle, small hack if there is no progress (angle_end = 0 results in full progress)
            Color(1, 0, 0)
            Ellipse(pos=self.pos, size=self.size,
                    angle_end=(0.001 if self.value_normalized == 0 else self.value_normalized*360))

            # Draw the inner circle (colour should be equal to the background)
            Color(0, 0, 0)
            Ellipse(pos=(self.pos[0] + self.thickness / 2, self.pos[1] + self.thickness / 2),
                    size=(self.size[0] - self.thickness, self.size[1] - self.thickness))

            # Center and draw the progress text
            Color(1, 1, 1, 1)
            Rectangle(texture=self.label.texture, size=self.texture_size,
                      pos=(self.size[0]/2 - self.texture_size[0]/2, self.size[1]/2 - self.texture_size[1]/2))

    def refresh_text(self):
        # Render the label
        self.label.refresh()

        # Set the texture size each refresh
        self.texture_size = list(self.label.texture.size)

    def set_value(self, value):
        # Update the progress bar value
        self.value = value

        # Update textual value and refresh the texture
        self.label.text = str(int(self.value_normalized*100)) + "%"
        self.refresh_text()

        # Draw all the elements
        self.draw()


class Main(App):

    def just_function(self):
        print(self.root) # <----- this will print None

    # Simple animation to show the circular progress bar in action
    def animate(self, dt):
        print(self.root) # <---- this prints CircularProgressBar object
        if self.root.value < 80:
            self.root.set_value(self.root.value + 1)
        else:
            self.root.set_value(0)

    # Simple layout for easy example
    def build(self):
        container = Builder.load_string(
            '''CircularProgressBar:
    size_hint: (None, None)
    height: 200
    width: 200
    max: 80''')

        # Animate the progress bar
        Clock.schedule_interval(self.animate, 0.1)
        print(self.root) # <---- this prints None
        self.just_function() # <---- this prints None
        return container


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

When you take a look at Main(App)

In this source, self.root is considered as CircularProgressBar in here.

But, when I do print(self.root) it prints None.

It only recognize CircularProgressBar when self.root is in a function that is called by Clock.scheduled_interval(func, rate).

Does anyone know what is happening in here?

标签: pythonkivy

解决方案


解释很简单,在文档中有清楚的解释:

根 = 无

如果 kv 文件包含根小部件,则由 build() 方法或 load_kv() 方法返回的根小部件。

从上面可以理解, therootbuild()方法中返回的元素,因此在返回该函数之前root将是None,因此当您在其中打印self.rootbuild()调用self.root在返回该函数之前打印的函数时,您将始终得到None。返回根之后,它将是您返回的内容,即containerclass 的对象CircularProgressBar


推荐阅读