0

I'm trying to make an app where I can display a circular progressbar, I've been told to use a FloatLayout so the arrangements stay organized no matter the size of the mobile screen. I've used this example for the circular progressbar How to make circular progress bar in kivy? , however, I can't seem to put the progressbar within the FloatLayout so that it organizes itself as I change the size of the screen. Anyone has a suggestion?

EDIT: I want the progressbar to stay at the center of the window, relatively based on the current window size and height. With the current code, when I change the size of the window, the progressbar doesn't relocate itself to the middle.

Here's the code I'm using:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
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, FloatLayout):
    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()
            Color(0.26,0.26,0.26)
            Ellipse(pos=self.pos, size=self.size)
            Color(1,0,0)
            Ellipse(pos=self.pos,size=self.size,angle_end=(self.value/100.0)*360)
            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))
            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()

class MainWindow(Screen, Widget):
    current = ""

class WindowManager(ScreenManager):
    pass

kv = Builder.load_file("main.kv")
sm = WindowManager()
screens = [MainWindow(name="main")]
for screen in screens:
    sm.add_widget(screen)

sm.current = "main"

class Main(App):
    def animate(self,dt):
        circProgressBar = self.root.get_screen('main').ids.cp
        if circProgressBar.value < 99:
            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__":
    Main().run()

Here is the .kv file:

WindowManager:
    MainWindow:

<MainWindow>:
    name: "main"

    FloatLayout:
        CircularProgressBar:
            id: cp
            pos: 250, 250
            size_hint:(None,None)
            height:200
            width:200
            max:100

Ded Meme
  • 1
  • 1
  • What do you mean by "organizes itself"? What do you expect to see? – John Anderson Aug 31 '21 at 18:19
  • I mean it as in the progressbar stays located in a specific place relatively based on the current window size and height. For example, I want to keep the progressbar at the center of the screen, however, if I change the size of the window, the progressbar doesn't relocate. – Ded Meme Sep 05 '21 at 16:25

1 Answers1

0

You can accomplish that by using pos_hint to set the position of the CircularProgressBar, and then making sure that everything in your draw() method is based on that position. For example, here is pos_hint in your kv:

WindowManager:
    MainWindow:

<MainWindow>:
    name: "main"

    FloatLayout:
        CircularProgressBar:
            id: cp
            pos_hint: {'center_x': 0.5, 'center_y': 0.5}
            size_hint:(None,None)
            height:200
            width:200
            max:100

Then your draw() method can be:

def draw(self):
    with self.canvas:
        self.canvas.clear()
        Color(0.26,0.26,0.26)
        Ellipse(pos=self.pos, size=self.size)
        Color(1,0,0)
        Ellipse(pos=self.pos,size=self.size,angle_end=(self.value/100.0)*360)
        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))
        Color(1, 1, 1, 1)
        Rectangle(texture=self.label.texture,size=self.texture_size,pos=(self.pos[0]-self.texture_size[0],self.center[1] - self.texture_size[1]/2))
        self.label.text = str(int(self.value))

The only modification to your draw() method is in the pos of the Rectangle.

John Anderson
  • 35,991
  • 4
  • 13
  • 36