#encoding: utf-8 from Tkinter import Tk, Canvas, Frame, SEL_FIRST, SEL_LAST class NewHScale(Canvas): __slots__ = ('frame', 'value', '_max', '_min', 'text', 'grad', 'font') def __init__(self, parent, text, width=200, height=24, font='Courier 8 bold', _min=0, _max=255, gradient='none'): self.frame = Frame(parent, bd=2, relief='ridge') Canvas.__init__(self, self.frame) Canvas.grid(self, column=0, row=0, sticky='nw') self._min = _min self._max = _max self.value = self._min + ((self._max - self._min) / 2) self.text = text self.font = font if gradient in ['vertical', 'horizontal', 'none']: self.grad = gradient else: self.grad = 'none' self.config(borderwidth=0, height=height, width=width, selectborderwidth=0, highlightthickness=0, cursor='sb_h_double_arrow') self.bind('', self.__select_value) self.bind('', self.__repaint_widget) self.bind('', self.__repaint_widget) self.__repaint_widget() def __canvas2value(self, pos): ''' Přepočítá grafickou souřadnici z canvasu na hodnotu proměnné ''' rozsah = self._max - self._min x = (pos * rozsah) / float(self['width']) return x + self._min def __value2canvas(self): ''' Z hodnoty value přepočítá souřadnici pro canvas ''' rozsah = self._max - self._min x = ((self.value - self._min) * float(self['width'])) / rozsah return int(x) def __convert_RGB(self, r, g, b): return '#%02X%02X%02X' % (r, g, b) def __gradient_fill(self, width, start_col=(220, 220, 220), end_col=(50, 50, 50), typ='vertical'): x1, x2 = 0, int(width) y1, y2 = 0, int(self['height']) h = int(y2 - y1) if typ == 'vertical' else int(x2 - x1) step = ( float(end_col[0] - start_col[0]) / h, float(end_col[1] - start_col[1]) / h, float(end_col[2] - start_col[2]) / h) if typ == 'vertical': for line in xrange(y1, y2): color = self.__convert_RGB( min(max(start_col[0]+(step[0]*(line-y1)),0),255), min(max(start_col[1]+(step[1]*(line-y1)),0),255), min(max(start_col[2]+(step[2]*(line-y1)),0),255)) self.create_line(x1, line, x2, line, fill=color) else: for col in xrange(x1, x2): color = self.__convert_RGB( min(max(start_col[0]+(step[0]*(col-x1)),0),255), min(max(start_col[1]+(step[1]*(col-x1)),0),255), min(max(start_col[2]+(step[2]*(col-x1)),0),255)) self.create_line(col, y1, col, y2, fill=color) def __repaint_widget(self, event=None): x = self.__value2canvas() if event is not None: x = self.canvasx(event.x) self.value = self.__canvas2value(x) if self.value < self._min : self.value = self._min elif self.value > self._max: self.value = self._max self.delete('all') if self.grad is 'vertical': self.__gradient_fill(x, typ='vertical') elif self.grad is 'horizontal': self.__gradient_fill(x, typ='horizontal') else: self.create_rectangle(0, 0, x, int(self['height']), fill='cyan', outline='cyan') self.create_text(2, 2, anchor='nw', text=self.text, font=self.font) self.create_text(int(self['width']), int(self['height']), anchor='se', text=str(self.value), font=self.font, tags=('value')) def __select_value(self, event): self.bind('', self.__edit_value) item = self.find_withtag('value') self.focus_set() self.focus(item) self.select_from(item, 0) self.select_to(item, 'end') x, y = map(int, self.coords(item)) self.icursor(item, '@%d,%d' % (x, y)) self.dchars(item, SEL_FIRST, SEL_LAST) self.select_clear() def __edit_value(self, event): item = self.find_withtag('value') insert = self.index(item, 'insert') if event.char in ['.', '-'] + map(str, range(10)): self.insert(item, 'insert', event.char) if event.keysym == 'Return': try: self.value = float(self.itemcget(item, 'text')) except: self.value = self._min self.unbind('') self.__repaint_widget() elif event.keysym == 'BackSpace': self.dchars(item, insert-1) self.icursor(item, insert-1) elif event.keysym == 'Left': self.icursor(item, insert-1) elif event.keysym == 'Right': self.icurser(item, insert+1) def change(self, gradient='none'): self.grad = gradient def get(self): return self.value def grid(self, **kw): self.frame.grid(**kw) def pack(self, **kw): self.frame.pack(**kw) def place(self, **kw): self.frame.place(**kw) if __name__ == '__main__': app = Tk() app.geometry('220x50') a = NewHScale(app, 'Constitution', _min=-100, gradient='vertical') a.grid(column=0, row=0, sticky='nw') app.mainloop()