Skip to content

Commit b7db195

Browse files
Merge pull request slightlynybbled#38 from naejgz/master
Adding Gauge2
2 parents e6af77e + 258d0a6 commit b7db195

7 files changed

Lines changed: 276 additions & 20 deletions

File tree

.directory

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[Dolphin]
2+
SortRole=modificationtime
3+
Timestamp=2018,6,9,11,51,23
4+
Version=4
5+
ViewMode=1

docs/img/gauge2doc.png

60.2 KB
Loading

docs/img/gauges2.png

59.9 KB
Loading

examples/gauge2.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import tkinter as tk
2+
import tk_tools
3+
4+
5+
root = tk.Tk()
6+
7+
max_speed = 20000
8+
9+
speed_gauge = tk_tools.Gauge2(root,
10+
max_value=max_speed,
11+
label='speed', unit=' m/h',bg='grey')
12+
speed_gauge.grid(row=0, column=0, sticky='news')
13+
14+
15+
tach_gauge = tk_tools.Gauge2(root,
16+
max_value=8000,
17+
label='tach', unit=' RPM',
18+
divisions=10)
19+
tach_gauge.grid(row=1, column=0, sticky='news')
20+
21+
strange_gauge = tk_tools.Gauge2(root,
22+
max_value=30000,
23+
label='strange', unit=' blah',
24+
divisions=10, red=90, yellow=60)
25+
strange_gauge.grid(row=2, column=0, sticky='news')
26+
27+
batV_gauge = tk_tools.Gauge2(root, height=120, width=250,
28+
max_value=16, min_value=8,
29+
label='Bat voltage', unit='V',
30+
divisions=8, yellow=60, red=75,
31+
red_low=30, yellow_low=40)
32+
batV_gauge.grid(row=0, column=1, sticky='news')
33+
34+
batI_gauge = tk_tools.Gauge2(root, height=120, width=250,
35+
max_value=6, min_value=-8,
36+
label='Bat current', unit='A',
37+
divisions=14, yellow=80, red=90,
38+
red_low=20, yellow_low=30,bg='lavender')
39+
batI_gauge.grid(row=1, column=1, sticky='news')
40+
41+
count = 0
42+
up = True
43+
44+
45+
def update_gauge():
46+
global count, up
47+
48+
increment = 30
49+
50+
if up:
51+
count += increment
52+
if count > max_speed:
53+
up = False
54+
else:
55+
count -= increment
56+
57+
if count <= 0.0:
58+
up = True
59+
60+
speed_gauge.set_value(count)
61+
tach_gauge.set_value(count)
62+
strange_gauge.set_value(count)
63+
batV_gauge.set_value(count/1000)
64+
batI_gauge.set_value((count-10000)/1000)
65+
66+
root.after(50, update_gauge)
67+
68+
69+
root.after(100, update_gauge)
70+
71+
root.mainloop()

readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ Here are some examples screenshots of the widgets you can create:
5959

6060
![Gauges](docs/img/gauges.png)
6161

62+
#### Gauge2
63+
64+
![Gauges2](docs/img/gauges2.png)
65+
![Gauges2doc](docs/img/gauge2doc.png)
66+
6267
#### Rotary-Scale: (Tachymeter)
6368

6469
![Rotary-Scale](docs/img/rotary-scale.png)

tk_tools/__init__.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
from tk_tools.canvas import RotaryScale, Gauge, Graph, Led
2-
from tk_tools.groups import EntryGrid, LabelGrid, \
3-
KeyValueEntry, SpreadSheetReader, ButtonGrid, \
4-
Calendar, MultiSlotFrame, SevenSegment, SevenSegmentDigits
5-
from tk_tools.widgets import SmartOptionMenu, SmartSpinBox, \
6-
SmartCheckbutton, BinaryLabel, ByteLabel
7-
from tk_tools.tooltips import ToolTip
8-
9-
from tk_tools.version import __version__
10-
11-
12-
__all__ = [
13-
'RotaryScale', 'Gauge', 'Graph', 'Led',
14-
'EntryGrid', 'LabelGrid', 'ButtonGrid', 'KeyValueEntry',
15-
'SpreadSheetReader', 'SmartOptionMenu', 'SmartSpinBox',
16-
'SmartCheckbutton', 'Calendar', 'MultiSlotFrame',
17-
'SevenSegment', 'SevenSegmentDigits',
18-
'BinaryLabel', 'ByteLabel', 'ToolTip',
19-
'__version__'
20-
]
1+
from tk_tools.canvas import RotaryScale, Gauge, Graph, Led, Gauge2
2+
from tk_tools.groups import EntryGrid, LabelGrid, \
3+
KeyValueEntry, SpreadSheetReader, ButtonGrid, \
4+
Calendar, MultiSlotFrame, SevenSegment, SevenSegmentDigits
5+
from tk_tools.widgets import SmartOptionMenu, SmartSpinBox, \
6+
SmartCheckbutton, BinaryLabel, ByteLabel
7+
from tk_tools.tooltips import ToolTip
8+
9+
from tk_tools.version import __version__
10+
11+
12+
__all__ = [
13+
'RotaryScale', 'Gauge', 'Graph', 'Led', 'Gauge2',
14+
'EntryGrid', 'LabelGrid', 'ButtonGrid', 'KeyValueEntry',
15+
'SpreadSheetReader', 'SmartOptionMenu', 'SmartSpinBox',
16+
'SmartCheckbutton', 'Calendar', 'MultiSlotFrame',
17+
'SevenSegment', 'SevenSegmentDigits',
18+
'BinaryLabel', 'ByteLabel', 'ToolTip',
19+
'__version__'
20+
]

tk_tools/canvas.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,181 @@ def set_value(self, value):
305305

306306
self._redraw()
307307

308+
# Gauge2 : modifications from Gauge
309+
# ************************
310+
# 3 numeric values added : min, center, max,
311+
# and meter a bit flatter to accept center value
312+
# small correction of the rate for green yellow red zones
313+
# now 80% gives 2 red among 10 divisions
314+
# now yellow and red zone size can change
315+
# yellow and red zone also for too small values
316+
# readout still active with RED BG if values OFF limits
317+
# suppressed (commented) : create second half part
318+
# suppressed integer conversion on extend to not accumulate decimal loss errors
319+
# idem on value
320+
# math correction now min_value can be different from 0 or negative
321+
322+
323+
class Gauge2(ttk.Frame):
324+
"""
325+
Shows a gauge, much like the RotaryGauge::
326+
gauge = tk_tools.Gauge(root, max_value=100.0,
327+
label='speed', unit='km/h')
328+
gauge.grid()
329+
gauge.set_value(10)
330+
:param parent: tkinter parent frame
331+
:param width: canvas width
332+
:param height: canvas height
333+
:param min_value: the minimum value
334+
:param max_value: the maximum value
335+
:param label: the label on the scale
336+
:param unit: the unit to show on the scale
337+
:param divisions: the number of divisions on the scale
338+
:parm yellow: the beginning of the yellow (warning) zone in percent
339+
:parm red: the beginning of the red (danger) zone in percent
340+
:parm yellow_low: in percent warning for low values
341+
:parm red_low: in percent if very low values are a danger
342+
:param bg: background
343+
"""
344+
def __init__(self, parent, width=200, height=100,
345+
min_value=0.0, max_value=100.0, label='', unit='',
346+
divisions=8, yellow=50, red=80, yellow_low=0,
347+
red_low=0, bg='lightgrey'):
348+
self._parent = parent
349+
self._width = width
350+
self._height = height
351+
self._label = label
352+
self._unit = unit
353+
self._divisions = divisions
354+
self._min_value = EngNumber(min_value)
355+
self._max_value = EngNumber(max_value)
356+
self._average_value = EngNumber((max_value + min_value) / 2)
357+
self._yellow = yellow * 0.01
358+
self._red = red * 0.01
359+
self._yellow_low = yellow_low * 0.01
360+
self._red_low = red_low * 0.01
361+
362+
super().__init__(self._parent)
363+
364+
self._canvas = tk.Canvas(self, width=self._width,
365+
height=self._height, bg=bg)
366+
self._canvas.grid(row=0, column=0, sticky='news')
367+
self._min_value = EngNumber(min_value)
368+
self._max_value = EngNumber(max_value)
369+
self._value = self._min_value
370+
self._redraw()
371+
# ----------------------------------------------------------------------
372+
373+
def _redraw(self):
374+
self._canvas.delete('all')
375+
max_angle = 120.0
376+
value_as_percent = ((self._value - self._min_value) /
377+
(self._max_value - self._min_value))
378+
value = float(max_angle * value_as_percent)
379+
# no int() => accuracy
380+
# create the tick marks and colors across the top
381+
for i in range(self._divisions):
382+
extent = (max_angle / self._divisions)
383+
start = (150.0 - i * extent)
384+
rate = (i+1)/(self._divisions+1)
385+
if rate < self._red_low:
386+
bg_color = 'red'
387+
elif rate <= self._yellow_low:
388+
bg_color = 'yellow'
389+
elif rate <= self._yellow:
390+
bg_color = 'green'
391+
elif rate <= self._red:
392+
bg_color = 'yellow'
393+
else:
394+
bg_color = 'red'
395+
396+
self._canvas.create_arc(
397+
0, int(self._height * 0.15),
398+
self._width, int(self._height * 1.8),
399+
start=start, extent=-extent, width=2,
400+
fill=bg_color, style='pie'
401+
)
402+
bg_color = 'white'
403+
red = '#c21807'
404+
ratio = 0.06
405+
self._canvas.create_arc(self._width * ratio,
406+
int(self._height * 0.25),
407+
self._width * (1.0 - ratio),
408+
int(self._height * 1.8 * (1.0 - ratio * 1.1)),
409+
start=150, extent=-120, width=2,
410+
fill=bg_color, style='pie')
411+
# readout & title
412+
self.readout(self._value, 'black') # BG black if OK
413+
414+
# display lowest value
415+
value_text = '{}'.format(self._min_value)
416+
self._canvas.create_text(
417+
self._width * 0.1, self._height * 0.7,
418+
font=('Courier New', 10), text=value_text)
419+
# display greatest value
420+
value_text = '{}'.format(self._max_value)
421+
self._canvas.create_text(
422+
self._width * 0.9, self._height * 0.7,
423+
font=('Courier New', 10), text=value_text)
424+
# display center value
425+
value_text = '{}'.format(self._average_value)
426+
self._canvas.create_text(
427+
self._width * 0.5, self._height * 0.1,
428+
font=('Courier New', 10), text=value_text)
429+
# create first half (red needle)
430+
self._canvas.create_arc(0, int(self._height * 0.15),
431+
self._width, int(self._height * 1.8),
432+
start=150, extent=-value, width=3,
433+
outline=red)
434+
435+
# create second half
436+
'''self._canvas.create_arc(0, int(self._height * 0.15),
437+
self._width, int(self._height * 1.8),
438+
start=30, extent=120-value, width=3,
439+
outline=red)'''
440+
# create inset red
441+
self._canvas.create_arc(self._width * 0.35, int(self._height * 0.7),
442+
self._width * 0.65, int(self._height * 1.2),
443+
start=150, extent=-120, width=1,
444+
outline='grey', fill=red, style='pie')
445+
446+
# create the overlapping black border
447+
self._canvas.create_arc(0, int(self._height * 0.15),
448+
self._width, int(self._height * 1.8),
449+
start=150, extent=-120, width=3,
450+
outline='#343434')
451+
# ----------------------------------------------------------------------
452+
453+
def readout(self, value, bg): # value, BG color
454+
# draw the black behind the readout
455+
r_width = 95
456+
r_height = 20
457+
r_offset = 8
458+
self._canvas.create_rectangle(
459+
self._width/2.0 - r_width / 2.0,
460+
self._height/2.0 - r_height/2.0 + r_offset,
461+
self._width/2.0 + r_width / 2.0,
462+
self._height/2.0 + r_height/2.0 + r_offset,
463+
fill=bg, outline='grey'
464+
)
465+
# the digital readout
466+
self._canvas.create_text(
467+
self._width * 0.5, self._height * 0.5 - r_offset,
468+
font=('Courier New', 10), text=self._label)
469+
470+
value_text = '{}{}'.format(self._value, self._unit)
471+
self._canvas.create_text(
472+
self._width * 0.5, self._height * 0.5 + r_offset,
473+
font=('Courier New', 10), text=value_text, fill='white')
474+
# ----------------------------------------------------------------------
475+
476+
def set_value(self, value):
477+
self._value = EngNumber(value)
478+
if self._min_value * 1.02 < value < self._max_value * 0.98:
479+
self._redraw() # refresh all
480+
else: # OFF limits refresh only readout
481+
self.readout(self._value, 'red') # on RED BackGround
482+
308483

309484
class Graph(ttk.Frame):
310485
"""

0 commit comments

Comments
 (0)