337 lines
8.3 KiB
Python
337 lines
8.3 KiB
Python
|
"""
|
||
|
Components/ProgressBar
|
||
|
======================
|
||
|
|
||
|
.. seealso::
|
||
|
|
||
|
`Material Design spec, Progress indicators <https://material.io/components/progress-indicators>`_
|
||
|
|
||
|
.. rubric:: Progress indicators express an unspecified wait time or display
|
||
|
the length of a process.
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-preview.png
|
||
|
:align: center
|
||
|
|
||
|
`KivyMD` provides the following bars classes for use:
|
||
|
|
||
|
- MDProgressBar_
|
||
|
- Determinate_
|
||
|
- Indeterminate_
|
||
|
|
||
|
.. MDProgressBar:
|
||
|
MDProgressBar
|
||
|
-------------
|
||
|
|
||
|
.. code-block:: python
|
||
|
|
||
|
from kivy.lang import Builder
|
||
|
|
||
|
from kivymd.app import MDApp
|
||
|
|
||
|
KV = '''
|
||
|
MDBoxLayout:
|
||
|
padding: "10dp"
|
||
|
|
||
|
MDProgressBar:
|
||
|
value: 50
|
||
|
'''
|
||
|
|
||
|
|
||
|
class Test(MDApp):
|
||
|
def build(self):
|
||
|
return Builder.load_string(KV)
|
||
|
|
||
|
|
||
|
Test().run()
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar.png
|
||
|
:align: center
|
||
|
|
||
|
Vertical orientation
|
||
|
--------------------
|
||
|
|
||
|
.. code-block:: kv
|
||
|
|
||
|
MDProgressBar:
|
||
|
orientation: "vertical"
|
||
|
value: 50
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-vertical.png
|
||
|
:align: center
|
||
|
|
||
|
With custom color
|
||
|
-----------------
|
||
|
|
||
|
.. code-block:: kv
|
||
|
|
||
|
MDProgressBar:
|
||
|
value: 50
|
||
|
color: app.theme_cls.accent_color
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-custom-color.png
|
||
|
:align: center
|
||
|
|
||
|
.. Indeterminate:
|
||
|
Indeterminate
|
||
|
-------------
|
||
|
|
||
|
.. code-block:: python
|
||
|
|
||
|
from kivy.lang import Builder
|
||
|
from kivy.properties import StringProperty
|
||
|
|
||
|
from kivymd.app import MDApp
|
||
|
|
||
|
KV = '''
|
||
|
MDScreen:
|
||
|
|
||
|
MDProgressBar:
|
||
|
id: progress
|
||
|
pos_hint: {"center_y": .6}
|
||
|
type: "indeterminate"
|
||
|
|
||
|
MDRaisedButton:
|
||
|
text: "STOP" if app.state == "start" else "START"
|
||
|
pos_hint: {"center_x": .5, "center_y": .45}
|
||
|
on_press: app.state = "stop" if app.state == "start" else "start"
|
||
|
'''
|
||
|
|
||
|
|
||
|
class Test(MDApp):
|
||
|
state = StringProperty("stop")
|
||
|
|
||
|
def build(self):
|
||
|
return Builder.load_string(KV)
|
||
|
|
||
|
def on_state(self, instance, value):
|
||
|
{
|
||
|
"start": self.root.ids.progress.start,
|
||
|
"stop": self.root.ids.progress.stop,
|
||
|
}.get(value)()
|
||
|
|
||
|
|
||
|
Test().run()
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/indeterminate-progress-bar.gif
|
||
|
:align: center
|
||
|
|
||
|
.. Determinate:
|
||
|
Determinate
|
||
|
-----------
|
||
|
|
||
|
.. code-block:: kv
|
||
|
|
||
|
MDProgressBar:
|
||
|
type: "determinate"
|
||
|
running_duration: 1
|
||
|
catching_duration: 1.5
|
||
|
|
||
|
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/determinate-progress-bar.gif
|
||
|
:align: center
|
||
|
"""
|
||
|
|
||
|
__all__ = ("MDProgressBar",)
|
||
|
|
||
|
import os
|
||
|
from typing import Union
|
||
|
|
||
|
from kivy.animation import Animation
|
||
|
from kivy.clock import Clock
|
||
|
from kivy.lang import Builder
|
||
|
from kivy.metrics import dp
|
||
|
from kivy.properties import (
|
||
|
BooleanProperty,
|
||
|
ColorProperty,
|
||
|
NumericProperty,
|
||
|
OptionProperty,
|
||
|
StringProperty,
|
||
|
VariableListProperty,
|
||
|
)
|
||
|
from kivy.uix.progressbar import ProgressBar
|
||
|
|
||
|
from kivymd import uix_path
|
||
|
from kivymd.theming import ThemableBehavior
|
||
|
|
||
|
with open(
|
||
|
os.path.join(uix_path, "progressbar", "progressbar.kv"), encoding="utf-8"
|
||
|
) as kv_file:
|
||
|
Builder.load_string(kv_file.read())
|
||
|
|
||
|
|
||
|
class MDProgressBar(ThemableBehavior, ProgressBar):
|
||
|
"""
|
||
|
Progressbar class.
|
||
|
|
||
|
For more information, see in the
|
||
|
:class:`~kivymd.theming.ThemableBehavior` and
|
||
|
:class:`~kivy.uix.progressbar.ProgressBar`
|
||
|
classes documentation.
|
||
|
"""
|
||
|
|
||
|
radius = VariableListProperty([0], length=4)
|
||
|
"""
|
||
|
Progress line radius.
|
||
|
|
||
|
.. versionadded:: 1.2.0
|
||
|
|
||
|
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
|
||
|
and defaults to `[0, 0, 0, 0]`.
|
||
|
"""
|
||
|
|
||
|
reversed = BooleanProperty(False)
|
||
|
"""
|
||
|
Reverse the direction the progressbar moves.
|
||
|
|
||
|
:attr:`reversed` is an :class:`~kivy.properties.BooleanProperty`
|
||
|
and defaults to `False`.
|
||
|
"""
|
||
|
|
||
|
orientation = OptionProperty(
|
||
|
"horizontal", options=["horizontal", "vertical"]
|
||
|
)
|
||
|
"""
|
||
|
Orientation of progressbar. Available options are: `'horizontal '`,
|
||
|
`'vertical'`.
|
||
|
|
||
|
:attr:`orientation` is an :class:`~kivy.properties.OptionProperty`
|
||
|
and defaults to `'horizontal'`.
|
||
|
"""
|
||
|
|
||
|
color = ColorProperty(None)
|
||
|
"""
|
||
|
Progress bar color in (r, g, b, a) or string format.
|
||
|
|
||
|
:attr:`color` is an :class:`~kivy.properties.ColorProperty`
|
||
|
and defaults to `None`.
|
||
|
"""
|
||
|
|
||
|
back_color = ColorProperty(None)
|
||
|
"""
|
||
|
Progress bar back color in (r, g, b, a) or string format.
|
||
|
|
||
|
.. versionadded:: 1.0.0
|
||
|
|
||
|
:attr:`back_color` is an :class:`~kivy.properties.ColorProperty`
|
||
|
and defaults to `None`.
|
||
|
"""
|
||
|
|
||
|
running_transition = StringProperty("in_cubic")
|
||
|
"""
|
||
|
Running transition.
|
||
|
|
||
|
:attr:`running_transition` is an :class:`~kivy.properties.StringProperty`
|
||
|
and defaults to `'in_cubic'`.
|
||
|
"""
|
||
|
|
||
|
catching_transition = StringProperty("out_quart")
|
||
|
"""
|
||
|
Catching transition.
|
||
|
|
||
|
:attr:`catching_transition` is an :class:`~kivy.properties.StringProperty`
|
||
|
and defaults to `'out_quart'`.
|
||
|
"""
|
||
|
|
||
|
running_duration = NumericProperty(0.5)
|
||
|
"""
|
||
|
Running duration.
|
||
|
|
||
|
:attr:`running_duration` is an :class:`~kivy.properties.NumericProperty`
|
||
|
and defaults to `0.5`.
|
||
|
"""
|
||
|
|
||
|
catching_duration = NumericProperty(0.8)
|
||
|
"""
|
||
|
Catching duration.
|
||
|
|
||
|
:attr:`running_duration` is an :class:`~kivy.properties.NumericProperty`
|
||
|
and defaults to `0.8`.
|
||
|
"""
|
||
|
|
||
|
type = OptionProperty(
|
||
|
None, options=["indeterminate", "determinate"], allownone=True
|
||
|
)
|
||
|
"""
|
||
|
Type of progressbar. Available options are: `'indeterminate '`,
|
||
|
`'determinate'`.
|
||
|
|
||
|
:attr:`type` is an :class:`~kivy.properties.OptionProperty`
|
||
|
and defaults to `None`.
|
||
|
"""
|
||
|
|
||
|
_x = NumericProperty(0)
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
self.catching_anim = None
|
||
|
self.running_anim = None
|
||
|
super().__init__(**kwargs)
|
||
|
Clock.schedule_once(self.check_size)
|
||
|
|
||
|
def check_size(self, interval: Union[int, float]) -> None:
|
||
|
if self.height == 100:
|
||
|
if self.orientation == "horizontal":
|
||
|
self.size_hint_y = None
|
||
|
self.height = dp(4)
|
||
|
elif self.orientation == "vertical":
|
||
|
self.size_hint_x = None
|
||
|
self.width = dp(4)
|
||
|
|
||
|
def start(self) -> None:
|
||
|
"""Start animation."""
|
||
|
|
||
|
if self.type in ("indeterminate", "determinate"):
|
||
|
Clock.schedule_once(self._set_default_value)
|
||
|
if not self.catching_anim and not self.running_anim:
|
||
|
if self.type == "indeterminate":
|
||
|
self._create_indeterminate_animations()
|
||
|
else:
|
||
|
self._create_determinate_animations()
|
||
|
self.running_away()
|
||
|
|
||
|
def stop(self) -> None:
|
||
|
"""Stop animation."""
|
||
|
|
||
|
Animation.cancel_all(self)
|
||
|
self._set_default_value(0)
|
||
|
|
||
|
def running_away(self, *args) -> None:
|
||
|
self._set_default_value(0)
|
||
|
self.running_anim.start(self)
|
||
|
|
||
|
def catching_up(self, *args) -> None:
|
||
|
if self.type == "indeterminate":
|
||
|
self.reversed = True
|
||
|
self.catching_anim.start(self)
|
||
|
|
||
|
def _create_determinate_animations(self):
|
||
|
self.running_anim = Animation(
|
||
|
value=100,
|
||
|
opacity=1,
|
||
|
t=self.running_transition,
|
||
|
d=self.running_duration,
|
||
|
)
|
||
|
self.running_anim.bind(on_complete=self.catching_up)
|
||
|
self.catching_anim = Animation(
|
||
|
opacity=0,
|
||
|
t=self.catching_transition,
|
||
|
d=self.catching_duration,
|
||
|
)
|
||
|
self.catching_anim.bind(on_complete=self.running_away)
|
||
|
|
||
|
def _create_indeterminate_animations(self):
|
||
|
self.running_anim = Animation(
|
||
|
_x=self.width / 2,
|
||
|
value=50,
|
||
|
t=self.running_transition,
|
||
|
d=self.running_duration,
|
||
|
)
|
||
|
self.running_anim.bind(on_complete=self.catching_up)
|
||
|
self.catching_anim = Animation(
|
||
|
value=0, t=self.catching_transition, d=self.catching_duration
|
||
|
)
|
||
|
self.catching_anim.bind(on_complete=self.running_away)
|
||
|
|
||
|
def _set_default_value(self, interval):
|
||
|
self._x = 0
|
||
|
self.value = 0
|
||
|
self.reversed = False
|