| 1 | """ |
| 2 | I needed a simple gauge, so I've made on with Pmw. |
| 3 | It might be useful for others to use as a base to develop more comples |
| 4 | gauges with. |
| 5 | |
| 6 | Is it worth cleaning up and submitting? |
| 7 | |
| 8 | cheers and thanks |
| 9 | |
| 10 | chris |
| 11 | |
| 12 | Dr. Chris Wright |
| 13 | Intensive Care Unit |
| 14 | Monash Medical Centre |
| 15 | Clayton. VIC Australia |
| 16 | """ |
| 17 | |
| 18 | import sys |
| 19 | import Tkinter |
| 20 | import Pmw |
| 21 | import time |
| 22 | |
| 23 | |
| 24 | if 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" |
| 30 | else: |
| 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 | |
| 37 | class 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 | |
| 220 | Pmw.forwardmethods(VerticalGauge, Tkinter.Canvas, 'canvas') |
| 221 | |
| 222 | if __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() |