Add a flood gauge style progressbar with label
See original GitHub issueThe idea behind this widget style is that it is similar to a card you would see commonly on a dashboard that includes text. It is essentially a progressbar with text in the middle. And, it can be used exactly as a progressbar, with some adjustments to the text size and thickness.
This style can be created by adding a custom layout based on the progressbar
and the label
.
I’ve decided to use a brightened and desaturated color for the progressbar background so that I have no need to change the text color when the gauge is filled past the 50% mark.
The method below would be added to the StylerTTK
class. The code currently reflects the primary color styles. The other colors would be the same logic, with just an iteration over the other available colors.
def _style_floodgauge(self):
"""
Create a style configuration for the *ttk.Progressbar* that makes it into a floodgauge. Which is essentially
a very large progress bar with text in the middle.
The options available in this widget include:
- Floodgauge.trough: borderwidth, troughcolor, troughrelief
- Floodgauge.pbar: orient, thickness, barsize, pbarrelief, borderwidth, background
- Floodgauge.text: 'text', 'font', 'foreground', 'underline', 'width', 'anchor', 'justify', 'wraplength',
'embossed'
"""
self.settings.update({
'Floodgauge.trough': {'element create': ('from', 'clam')},
'Floodgauge.pbar': {'element create': ('from', 'default')},
'Horizontal.TFloodgauge': {
'layout': [('Floodgauge.trough', {'children': [
('Floodgauge.pbar', {'side': 'left', 'sticky': 'ns'}),
("Floodgauge.label", {"sticky": ""})],
'sticky': 'nswe'})],
'configure': {
'thickness': 100,
'borderwidth': 1,
'bordercolor': self.theme.colors.primary,
'lightcolor': self.theme.colors.primary,
'pbarrelief': 'flat',
'troughcolor': Colors.update_hsv(self.theme.colors.primary, sd=-0.3, vd=0.8),
'background': self.theme.colors.primary,
'foreground': self.theme.colors.selectfg,
'justify': 'center',
'anchor': 'center',
'font': 'helvetica 16'}},
'Vertical.TFloodgauge': {
'layout': [('Floodgauge.trough', {'children': [
('Floodgauge.pbar', {'side': 'bottom', 'sticky': 'we'}),
("Floodgauge.label", {"sticky": ""})],
'sticky': 'nswe'})],
'configure': {
'thickness': 100,
'borderwidth': 1,
'bordercolor': self.theme.colors.primary,
'lightcolor': self.theme.colors.primary,
'pbarrelief': 'flat',
'troughcolor': Colors.update_hsv(self.theme.colors.primary, sd=-0.3, vd=0.8),
'background': self.theme.colors.primary,
'foreground': self.theme.colors.selectfg,
'justify': 'center',
'anchor': 'center',
'font': 'helvetica 16'}
}})
Below is a prototype of the Floodgauge class. I will have to handle the label options separately because TCL doesn’t understand a hybrid widget. The progressbar takes priority, so an error will occur if I try to pass through the text options to the superclass constructor. However, these options can still manipulated in the style since they actually exist in the layout. To get around this, I’ve created a hack that generates a unique style based on the one passed into the constructor that can be altered continuously. I believe this is similar to the approach taken by other developers (eg. PySimpleGUI) for creating custom styles on each button.
In the case of changing the text. I’ve set a trace
on the textvariable so that it updates the widget every time the textvariable
changes.
import tkinter as tk
from tkinter import ttk
from ttkbootstrap import Style
from uuid import uuid4
class Floodgauge(ttk.Progressbar):
def __init__(self, parent, **kw):
_style = kw.get('style') or 'TFloodgauge'
_id = uuid4()
_orient = kw.get('orient').title() or 'Horizontal'
self._widgetstyle = f'{_id}.{_orient}.{_style}'
parent.tk.call("ttk::style", "configure", self._widgetstyle, '-%s' % None, None, None)
kwargs = {k: v for k, v in kw.items() if k not in ['text']}
self.textvariable = kw.get('textvariable') or tk.StringVar(value=kw.get('text'))
self.textvariable.trace_add('write', self._textvariable_write)
self.variable = kw.get('variable') or tk.IntVar(value=kw.get('value') or 0)
super().__init__(parent, class_='Floodgauge', style=self._widgetstyle, variable=self.variable, **kwargs)
@property
def text(self):
return self.textvariable.get()
@text.setter
def text(self, value):
self.textvariable.set(value)
@property
def value(self):
return self.variable.get()
@value.setter
def value(self, value):
self.variable.set(value)
def _textvariable_write(self, *args):
"""
Update the label text when there is a `write` action on the textvariable
"""
self.tk.call("ttk::style", "configure", self._widgetstyle, '-%s' % 'text', self.textvariable.get(), None)
if __name__ == '__main__':
root = tk.Tk()
root.geometry('400x400')
s = Style()
p = Floodgauge(root, value=55, text='55', orient='vertical')
def auto(progress):
p.text = f'Memory Usage\n{p.value}%'
p.step(1)
p.after(50, auto, p)
p.pack(fill='both', padx=20, pady=20, expand='yes')
auto(p)
root.mainloop()
Issue Analytics
- State:
- Created 2 years ago
- Comments:16 (7 by maintainers)
Top GitHub Comments
@RocksWon the round scrollbar isn’t in 0.5, mainly due to the limitation of having to create so many images. This is one of the things I changed in 1.0, where I am only creating the themes and styles that are used on-demand, instead of what is typically done with ttk themes, which is loading all the assets and building the styles first. However, by having so many pre-defined styles available, this caused memory issues.
Here is an issue that describes some of the changes made to 0.5 -> https://github.com/israel-dryer/ttkbootstrap/issues/82
Glad to hear it’s working. Added some fixes, and also added the calendar widgets.
https://ttkbootstrap.readthedocs.io/en/latest/widgets/calendar.html