Rahul N Kamath
Rahul N Kamath

Reputation: 3

In Kivy, how do I add a CircularProgressBar on a particular screen in an application with multiple screens?

I am trying to work on an Kivy application that displays certain data in the form of a Circular Progress Bar. I learnt about Circular Progress Bar through this link: How to make circular progress bar in kivy? However, I am unable to add this widget onto a particular screen.

I wish to embed the widget onto my screen and include a few other widgets. I have tried making a separate .kv file but it didn't work either. Here is my code. I wish to have the Circular Progress Bar inside my HomePage.

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
from kivy.uix.screenmanager import Screen, ScreenManager

Builder.load_string('''
<HomePage>:
    FloatLayout:
        canvas.before:
            Rectangle:
                # self here refers to the widget i.e BoxLayout
                pos: self.pos
                size: self.size
        CircularProgressBar:
            size_hint:(None,None)
            height:400
            width:400
            max:80
    ''')


class HomePage(Screen):
    pass
class CircularProgressBar(ProgressBar):
    def __init__(self,**kwargs):
        super(CircularProgressBar,self).__init__(**kwargs)
        self.thickness = 40
        self.label = CoreLabel(text="0",font_size=self.thickness)
        self.texture_size= None
        self.refresh_text()
        self.draw()
    def draw(self):
        with self.canvas:
            self.canvas.clear()
            #No progress
            Color(0.26,0.26,0.26)
            Ellipse(pos=self.pos, size=self.size)
            #Progress Circle
            Color(1,0,0)
            Ellipse(pos=self.pos,size=self.size,angle_end=0.5*360)#will be replaced with necessary data
            #Inner Circle
            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))
            #Inner 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))
            self.label.text = str(int(0.5*100))
    def refresh_text(self):
        self.label.refresh()
        self.texture_size=list(self.label.texture.size)
    def set_value(self, value):
        self.value = value
        self.label.text = str(int(0.5*100))
        self.refresh_text()
        self.draw()

sm = ScreenManager()
sm.add_widget(HomePage(name="HomePage"))

class HealthTrackingSystem(App):
    def animate(self,dt):
        if self.root.value<80:
            self.root.set_value(self.root.set_value+1)
        else:
            self.root.set_value(0)

    def build(self):
        Clock.schedule_interval(self.animate, 0.1)
        return sm

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

I am encountering the following error on running my code:

 File "HealthTrackingSystem.py", line 70, in animate
 if self.root.value<80
 'ScreenManager' object has no attribute 'value'

Upvotes: 0

Views: 672

Answers (1)

John Anderson
John Anderson

Reputation: 38857

In your code, self.root is the ScreenManager that you returned in your build method. You may want to add an id to your CircularProgressBar: (in the kv), and then use that to reference your CircularProgressBar.

Here is what it would look like (including edits to get the CircularProgressBar to work):

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
from kivy.uix.screenmanager import Screen, ScreenManager

Builder.load_string('''
<HomePage>:
    FloatLayout:
        canvas.before:
            Rectangle:
                # self here refers to the widget i.e BoxLayout
                pos: self.pos
                size: self.size
        CircularProgressBar:
            id: cp
            size_hint:(None,None)
            height:400
            width:400
            max:80
    ''')


class HomePage(Screen):
    pass
class CircularProgressBar(ProgressBar):
    def __init__(self,**kwargs):
        super(CircularProgressBar,self).__init__(**kwargs)
        self.thickness = 40
        self.label = CoreLabel(text="0",font_size=self.thickness)
        self.texture_size= None
        self.refresh_text()
        self.draw()
    def draw(self):
        with self.canvas:
            self.canvas.clear()
            #No progress
            Color(0.26,0.26,0.26)
            Ellipse(pos=self.pos, size=self.size)
            #Progress Circle
            Color(1,0,0)
            Ellipse(pos=self.pos,size=self.size,angle_end=(self.value/100.0)*360)#will be replaced with necessary data
            #Inner Circle
            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))
            #Inner 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))
            self.label.text = str(int(self.value))
    def refresh_text(self):
        self.label.refresh()
        self.texture_size=list(self.label.texture.size)
    def set_value(self, value):
        self.value = value
        self.label.text = str(int(self.value))
        self.refresh_text()
        self.draw()

sm = ScreenManager()
sm.add_widget(HomePage(name="HomePage"))

class HealthTrackingSystem(App):
    def animate(self,dt):
        circProgressBar = self.root.get_screen('HomePage').ids.cp
        if circProgressBar.value<80:
            circProgressBar.set_value(circProgressBar.value+1)
        else:
            circProgressBar.set_value(0)

    def build(self):
        Clock.schedule_interval(self.animate, 0.1)
        return sm

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

Upvotes: 1

Related Questions