1"""
2I needed a simple gauge, so I've made on with Pmw.
3It might be useful for others to use as a base to develop more comples
4gauges with.
5
6Is it worth cleaning up and submitting?
7
8cheers and thanks
9
10chris
11
12Dr. Chris Wright
13Intensive Care Unit
14Monash Medical Centre
15Clayton. VIC Australia
16"""
17
18import sys
19import Tkinter
20import Pmw
21import time
22
23
24if sys.platform == 'win32':
25    # MS-Windows specific fonts
26    label_font = "-family Ariel  -size 12"
27    value_font = "-family Ariel  -size 12"
28    small_font = "-family {MS Sans Serif} -size 9 -weight bold"
29    header_font = "-family {MS Sans Serif} -weight bold"
30else:
31    # X-Windows specific fonts
32    label_font = "-*-helvetica-*-r-*-*-*-160-*-*-*-*-*-*"
33    value_font = "-*-courier-*-r-*-*-*-160-*-*-*-*-*-*"
34    small_font = "-*-helvetica-*-r-*-*-*-130-*-*-*-*-*-*"
35    header_font = "-*-helvetica-bold-r-*-*-*-150-*-*-*-*-*-*"
36
37class VerticalGauge(Pmw.MegaWidget):
38    """Vertical gauge with actual and desired settings"""
39
40    def __init__(self, parent = None, **kw):
41	optiondefs = (
42	    ('min', 0, None),
43	    ('max', 100, None),
44	    ('majortickinterval', 10, None),
45	    ('minortickinterval', 5, None),
46	    ('units', '', None),
47	    ('bg', 'grey', self._backgroundSet),
48	    ('actualvalue', 50, self._actualSet),
49	    ('desiredvalue', 50, self._desiredSet),
50	    ('actualcolour', 'yellow1', None),
51	    ('desiredcolour', 'turquoise1', None),
52	    ('label', 'Label', None),
53	    )
54	self.defineoptions(kw, optiondefs)
55	Pmw.MegaWidget.__init__(self, parent)
56
57	interior = self.interior()
58	interior.grid_rowconfigure(1, weight = 1)
59	for r in range(3):
60	    interior.grid_columnconfigure(r, weight = 1)
61
62	self.actuallabel = self.createcomponent('actualLabel',
63						(), None,
64						Tkinter.Label, (interior,),
65						text = '',
66						width = 3,
67						relief = 'sunken',
68						bd = 1,
69						fg = self['actualcolour'],
70						font = value_font)
71	self.actuallabel.grid(sticky = "nswe", row = 0, column = 0)
72
73	self.label = self.createcomponent('label',
74					  (), None,
75					  Tkinter.Label, (interior,),
76					  text = self['label'],
77					  relief = 'raised',
78					  font = label_font,
79					  fg = 'navy',
80					  bd = 2)
81	self.label.grid(sticky = "nsew", row = 0, column = 1)
82
83	self.desiredlabel = self.createcomponent('desiredLabel',
84						 (), None,
85						 Tkinter.Label, (interior,),
86						 text = '',
87						 width = 3,
88						 relief = 'sunken',
89						 bd = 1,
90						 fg = self['desiredcolour'],
91						 font = value_font)
92	self.desiredlabel.grid(sticky = "nswe", row = 0, column = 2)
93
94	self.canvas = self.createcomponent('canvas',
95					   (), None,
96					   Tkinter.Canvas, (interior,),
97					   width = 100,
98					   height = 300,
99					   bg = 'grey')
100
101	self.canvas.grid(sticky = "nsew", columnspan = 3, pady = 1)
102	self.canvas.bind("<Configure>", self._createGaugeAxes)
103
104	self._createGaugeAxes()
105
106	self.initialiseoptions()
107
108    def _createGaugeAxes(self, event = None):
109	min = self['min']
110	max = self['max']
111	units = self['units']
112	majortickinterval = self['majortickinterval']
113
114	gauge_range = max - min
115
116	c = self.canvas
117	c.delete("all")
118	if event:
119	    h, w = event.height, event.width
120	else:
121	    h = int(c.configure("height")[4])
122	    w = int(c.configure("width")[4])
123
124	self.lower = h - 15
125	self.upper = 15
126	self.middle = w / 2
127	c.create_line(self.middle, self.lower, self.middle, self.upper)
128
129	majortickcount = int((max - min) / majortickinterval)
130	self.axislength = self.lower - self.upper
131	self.majortickdistance = float(self.axislength) / majortickcount
132	self.majortickwidth = w / 5
133	labeloffset = (w / 4) + 10
134
135	for i in range(majortickcount + 1):
136	    v = min + i * majortickinterval
137	    d = self.lower - i * self.majortickdistance
138	    c.create_line(self.middle, d, self.middle + self.majortickwidth, d)
139	    c.create_text(self.middle + labeloffset, d, font = small_font, text = str(v))
140
141	self._desiredSet(event)
142	self._actualSet(event)
143
144    def _backgroundSet(self):
145	self.canvas.configure(bg = self['bg'])
146
147    def _desiredSet(self, event = None):
148	c = self.canvas
149	desired = self['desiredvalue']
150	desiredcolour = self['desiredcolour']
151
152	min = self['min']
153	max = self['max']
154
155	if desired > max: desired = max
156	if desired < min: desired = min
157	gauge_range = max - min
158
159	c = self.canvas
160	if event:
161	    h, w = event.height, event.width
162	else:
163	    h = int(c.configure("height")[4])
164	    w = int(c.configure("width")[4])
165
166
167	desired_y = self.lower - (float(desired - min) / gauge_range) * self.axislength
168
169	try:
170	    c.delete('desiredBar')
171	except:
172	    pass
173
174	c.create_line(self.middle - self.majortickwidth, desired_y,
175		      self.middle + self.majortickwidth, desired_y,
176		      fill = desiredcolour, stipple = 'gray50',
177		      width = 10, tag = 'desiredBar')
178	self.desiredlabel.configure(text = desired)
179
180    def setActual(self, value):
181	self.configure(actualvalue = value)
182
183    def getActual(self):
184	return self.cget('actualvalue')
185
186    def _actualSet(self, event = None):
187	c = self.canvas
188	actual = self['actualvalue']
189	actualcolour = self['actualcolour']
190
191	min = self['min']
192	max = self['max']
193
194	if actual > max: actual = max
195	if actual < min: actual = min
196	gauge_range = max - min
197
198	c = self.canvas
199	if event:
200	    h, w = event.height, event.width
201	else:
202	    h = int(c.configure("height")[4])
203	    w = int(c.configure("width")[4])
204
205	actual_y = self.lower - (float(actual - min) / gauge_range) * self.axislength
206
207	try:
208	    c.delete('actualPointer')
209	except:
210	    pass
211
212	triangle = ((self.middle, actual_y),
213		    (self.middle - 1.4 * self.majortickwidth, actual_y - self.majortickwidth / 2),
214		    (self.middle - 1.4 * self.majortickwidth, actual_y + self.majortickwidth / 2))
215
216	c.create_polygon(triangle, fill = actualcolour, tag = 'actualPointer')
217	self.actuallabel.configure(text = actual)
218
219
220Pmw.forwardmethods(VerticalGauge, Tkinter.Canvas, 'canvas')
221
222if __name__ == '__main__':
223
224
225    # Initialise Tkinter and Pmw.
226    root = Pmw.initialise()
227    root.title('Pmw VerticalGauge demonstration')
228
229
230    def increase():
231	av = g1.getActual()
232	g1.setActual(av + 1)
233
234    def decrease():
235	av = g1.getActual()
236	g1.setActual(av - 1)
237
238    g1 = VerticalGauge(min = 0,
239		       max = 30,
240		       actualvalue = 15,
241		       desiredvalue = 22,
242		       majortickinterval = 2,
243		       label = "Pms")
244    g1.grid(sticky = "nsew")
245    root.grid_rowconfigure(0, weight = 1)
246    root.grid_columnconfigure(0, weight = 1)
247    b1 = Tkinter.Button(text = "Increase", command = increase)
248    b1.grid()
249    b2 = Tkinter.Button(text = "Decrease", command = decrease)
250    b2.grid()
251
252    # Let's go.
253    root.mainloop()
254