class Spacer(Frame): def __init__(self, parent, relief='raised', *args, **kw): apply(Frame.__init__, (self, parent) + args, kw) #self.grid_rowconfigure(0, weight=1) #self.grid_columnconfigure(1, weight=1) self.bg = self.cget('bg') self.relief = relief self.grid_columnconfigure(0, weight=1) self.canvas = Canvas(self, background=self.bg, width=1, height=6) self.canvas.grid(row=0, column=0, sticky=Tkinter.NSEW) #self.canvas.bind('<Configure>', self.resizeCallback) self.grid(sticky=Tkinter.EW) self.canvasL1 = [] self.canvasL2 = [] self.canvasL3 = [] self.refresh = 0 self.event = None self.bind('<Configure>', self.resizeAfter) def resizeAfter(self, event): self.event = event if self.refresh: return else: self.refresh = 1 self.after_idle(lambda: self.resize(self.event)) def resize(self, event): m = 6 w = event.width h = event.height N = int(h / m) self.canvas.config(width=w, height=h) if self.relief == 'sunken': fill1 = 'grey65' fill2 = 'grey95' else: fill1 = 'grey95' fill2 = 'grey65' for i in range(N): y = 1 + (i / float(N)) * h if i >= len(self.canvasL1): rect1 = self.canvas.create_rectangle(4, y + 0, w - 5, y + 2, width=0, fill=fill1) rect2 = self.canvas.create_rectangle(5, y + 1, w - 4, y + 3, width=0, fill=fill2) rect3 = self.canvas.create_rectangle(5, y + 1, w - 5, y + 2, width=0, fill=self.bg) self.canvasL1.append(rect1) self.canvasL2.append(rect2) self.canvasL3.append(rect3) else: self.canvas.coords(self.canvasL1[i], 4, y + 0, w - 5, y + 2) self.canvas.coords(self.canvasL2[i], 5, y + 1, w - 4, y + 3) self.canvas.coords(self.canvasL3[i], 5, y + 1, w - 5, y + 2) if N > len(self.canvasL1): for i in range(N, len(self.canvasL1)): self.canvas.delete(self.canvasL1[i]) self.canvas.delete(self.canvasL2[i]) self.canvas.delete(self.canvasL3[i]) self.refresh = 0
class LabelFrame(Frame): def __init__(self, parent, borderRelief='raised', text=' ', justify='left', width=None, font=None, height=None, docKey=None, tipText=None, *args, **kw): kw['borderwidth'] = self.bw = 18 Frame.__init__(self, parent, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) self.canvas2 = Canvas(self, background=self.bg) self.canvas3 = Canvas(self, background=self.bg) self.canvas4 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=None, tipText=tipText) self.canvasL1 = [] self.canvasL1a = [] self.canvasL2 = [] self.canvasL3 = [] self.canvasL3a = [] self.canvasL3b = [] self.canvasL4 = [] self.canvasL5 = [] self.canvasL5a = [] self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.bind('<Configure>', self.resize) def setText(self, text): self.label.set(text) self.resize() def resize(self, event=None): if event: w = event.width h = event.height else: w = int(self.winfo_width()) h = int(self.winfo_height()) self.after_idle(lambda: self.draw(w, h)) def draw(self, w, h): bw = self.bw pad = bw / 2 h2 = h - (2 * bw) textWidth = int(self.label.winfo_reqwidth()) if self.justify == 'left': textLeft = (3 * pad) + (0.05 * w) textRight = min(w, textLeft + textWidth) elif self.justify == 'right': textRight = (3 * pad) + (0.05 * w) textLeft = w - (textWidth + textRight) else: textLeft = (w / 2) - (textWidth / 2) textRight = textLeft + textWidth c1 = self.canvas1 c2 = self.canvas2 c3 = self.canvas3 c4 = self.canvas4 c1coords = c1.coords c2coords = c2.coords c3coords = c3.coords c4coords = c4.coords c1.place(x=0, y=0, anchor='nw', width=w, height=bw, bordermode='ignore') c2.place(x=0, y=bw, anchor='nw', width=bw, height=h2, bordermode='ignore') c3.place(x=0, y=h - bw, anchor='nw', width=w, height=bw, bordermode='ignore') c4.place(x=w - bw, y=bw, anchor='nw', width=bw, height=h2, bordermode='ignore') self.label.place(x=textLeft, y=0, anchor='nw', bordermode='ignore') e1, e2, e3 = self.canvasL1 c1coords(e1, pad, pad, textLeft - pad + 3, pad + 3) c1coords(e2, pad + 1, pad + 1, textLeft - pad + 3, pad + 3) c1coords(e3, pad + 1, pad + 1, textLeft - pad + 2, pad + 2) e1, e2, e3 = self.canvasL1a c1coords(e1, pad, pad, pad + 3, bw) c1coords(e2, pad + 1, pad + 1, pad + 3, bw) c1coords(e3, pad + 1, pad + 1, pad + 2, bw) e1, e2, e3 = self.canvasL2 c2coords(e1, pad, 0, pad + 3, h2) c2coords(e2, pad + 1, 0, pad + 3, h2) c2coords(e3, pad + 1, 0, pad + 2, h2) e1, e2, e3 = self.canvasL3 c3coords(e1, pad, pad, w - pad + 3, pad + 3) c3coords(e2, pad + 1, pad + 1, w - pad + 3, pad + 3) c3coords(e3, pad + 1, pad + 1, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL3a c3coords(e1, pad, 0, pad + 3, pad + 3) c3coords(e2, pad + 1, 0, pad + 3, pad + 3) c3coords(e3, pad + 1, 0, pad + 2, pad + 2) e1, e2, e3 = self.canvasL3b c3coords(e1, w - pad, 0, w - pad + 3, pad + 3) c3coords(e2, w - pad + 1, 0, w - pad + 3, pad + 3) c3coords(e3, w - pad + 1, 0, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL4 c4coords(e1, pad, 0, pad + 3, h2) c4coords(e2, pad + 1, 0, pad + 3, h2) c4coords(e3, pad + 1, 0, pad + 2, h2) e1, e2, e3 = self.canvasL5 c1coords(e1, textRight + pad, pad, w - pad + 3, pad + 3) c1coords(e2, textRight + pad + 1, pad + 1, w - pad + 3, pad + 3) c1coords(e3, textRight + pad + 1, pad + 1, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL5a c1coords(e1, w - pad, pad, w - pad + 3, bw) c1coords(e2, w - pad + 1, pad + 1, w - pad + 3, bw) c1coords(e3, w - pad + 1, pad + 1, w - pad + 2, bw)
class ProgressBar(BasePopup): def __init__(self, parent, text='', progress=0, total=100, title=None, width=200, height=15, transient=True, *args, **kw): self.progress = float(progress) self.cWidth = width self.cHeight = height self.total = float(total) or 1.0 self.text = text BasePopup.__init__(self, parent=parent, title=title or 'Progress Bar', transient=transient, *args, **kw) def body(self, parent): self.bw = 2 # borderwidth width = self.cWidth + self.bw height = self.cHeight + self.bw self.label = Label(parent, text=self.text) self.label.grid(row=0, column=0, sticky=Tkinter.W) self.percent = Label(parent, text=' %') self.percent.grid(row=0, column=2, sticky=Tkinter.W) self.canvas = Canvas(parent, background='grey70', width=width, height=height) self.canvas.grid(row=0, column=1, sticky=Tkinter.W) self.canvas.create_rectangle(0, 0, width, height, outline='black', width=self.bw) self.bar = self.canvas.create_rectangle(self.bw, self.bw, self.bw, self.cHeight, outline='#B05848', fill='#B05848', width=self.bw) self.update() def update(self): p = self.progress / self.total width = int(self.cWidth * p) self.canvas.coords(self.bar, self.bw, self.bw, width, self.cHeight) self.percent.set(' %3.1d' % int(100 * p) + "%") self.label.set(self.text) self.update_idletasks() if self.progress == self.total: time.sleep(0.1) self.close() def increment(self, n=1): p = self.progress + n self.progress = max(min(self.total, p), 0) self.update() def get(self): return self.progress / self.total def set(self, value): if value <= 1: self.progress = float(value) * self.total elif value <= self.total: self.progress = float(value) else: raise 'Cannot set to a value exceeding the total' self.update() def setText(self, text=''): self.text = text self.label.set(self.text)
class ColorChooser(Frame): def __init__(self, parent, *args, **kw): apply(Frame.__init__, (self, parent) + args, kw) self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(1, weight=0) self.grid_rowconfigure(2, weight=0) self.grid_rowconfigure(3, weight=0) self.canvas = Canvas(self, relief='sunken', borderwidth=2, width=150) self.canvas.grid(row=0, column=1, columnspan=1, sticky=Tkinter.NSEW, pady=2, padx=2) frame = Frame(self) frame.grid_columnconfigure(1, weight=1) self.boxSize = 100 self.numPixels = 10 self.pixelWidth = round(self.boxSize / self.numPixels) self.colorBox = Canvas(frame, relief='sunken', borderwidth=2, width=self.boxSize + 2, height=self.boxSize + 2) self.colorBox.bind('<Button-1>', self.pickInColorBox) self.colorBox.bind('<Button-2>', self.pickInColorBox) self.colorBox.bind('<Button-3>', self.pickInColorBox) self.colorBox.grid(row=0, column=2, rowspan=3, sticky=Tkinter.NSEW, padx=4, pady=4) self.pixel = [] self.colors = [] self.setupColorBox() self.scale = Tkinter.Scale(frame, orient=Tkinter.VERTICAL, length=self.boxSize, from_=0, to=99, label='', showvalue=0, command=self.refreshColorBox) self.scale.grid(row=0, column=3, rowspan=3, sticky=Tkinter.NS, padx=4, pady=4) frame.grid(row=1, column=0, columnspan=2, sticky=Tkinter.NSEW) labels = ('Red', 'Green', 'Blue') self.labeled_scale = 3 * [None] for n in range(3): label = Label(frame, text=labels[n] + ':', anchor=Tkinter.W) label.grid(row=n, column=0, sticky=Tkinter.EW) self.labeled_scale[n] = LabeledScale( frame, values=range(101), label_format='%3d', set_callback=self.scaleCallback) self.labeled_scale[n].grid(row=n, column=1, sticky=Tkinter.EW) def setupColorBox(self): pw = self.pixelWidth np = self.numPixels for x in range(np): self.pixel.append([]) self.colors.append([]) for y in range(np): rgb = hsbToRgb(0, 1 - x / float(np), 1 - y / float(np)) c = '#%02x%02x%02x' % (rgb[0] * 255, rgb[1] * 255, rgb[2] * 255) p = self.colorBox.create_rectangle(2 + pw * x, 2 + pw * y, 2 + (pw * x) + pw, (2 + pw * y) + pw, outline=c, fill=c) self.pixel[x].append(p) self.colors[x].append(rgb) def pickInColorBox(self, event): x = int(event.x / self.pixelWidth) y = int(event.y / self.pixelWidth) X = min(x, self.numPixels - 1) Y = min(y, self.numPixels - 1) x = max(X, 0) y = max(Y, 0) rgb = self.colors[x][y] self.setColor(rgb[0], rgb[1], rgb[2]) def refreshColorBox(self, H): np = self.numPixels H = int(H) / 100. for x in range(np): for y in range(np): rgb = hsbToRgb(H, 1 - x / float(np), 1 - y / float(np)) c = '#%02x%02x%02x' % (rgb[0] * 255, rgb[1] * 255, rgb[2] * 255) self.colorBox.itemconfigure(self.pixel[x][y], outline=c, fill=c) self.colors[x][y] = rgb def scaleCallback(self, *index): c = 3 * [0] for n in range(3): c[n] = int(2.559 * float(self.labeled_scale[n].getValue())) color = '#%02x%02x%02x' % (c[0], c[1], c[2]) self.canvas.config(bg=color) def setColor(self, r, g, b): c = (r, g, b) for n in range(3): s = round(100.0 * c[n]) s = min(100, s) self.labeled_scale[n].set(s) def getColor(self): c = 3 * [0] for n in range(3): c[n] = float(self.labeled_scale[n].getValue()) / 100.0 return tuple(c)
class ToggleArrow(Frame): def __init__(self, parent, arrowSize=11, outline='#5050b0', fill='#a0a0ff', isArrowClosed=True, callback=None, *args, **kw): self.arrowSize = arrowSize self.isArrowClosed = isArrowClosed self.callback = callback apply(Frame.__init__, (self, parent) + args, kw) bg = kw.get('bg') if (not bg): bg = kw.get('background') if (not bg): bg = parent.cget('bg') # below does not work for some reason, instead explicitly create rectangle below #self.canvas = Canvas(self, width=arrowSize, height=arrowSize, bg=bg) self.canvas = Canvas(self, width=arrowSize + 3, height=arrowSize + 1) self.canvas.grid(row=0, column=0) # need +/-1 otherwise get line along borders self.canvas.create_rectangle(-1, -1, arrowSize + 3, arrowSize + 1, fill=bg) # arbitrary coords self.arrow = self.canvas.create_polygon(0, 0, 1, 0, 1, 1, fill=fill, outline=outline) self.drawArrow() self.canvas.bind('<Button-1>', self.flipState) def drawArrow(self): s = self.arrowSize if (self.isArrowClosed): self.canvas.coords(self.arrow, 2, 0, s + 2, s / 2, 2, s) else: self.canvas.coords(self.arrow, 2, 0, s + 2, 0, (s / 2) + 2, s) def flipState(self, *event): self.isArrowClosed = not self.isArrowClosed if (self.callback): self.callback(self.isArrowClosed) self.drawArrow()
class LabelDivider(Frame): def __init__(self, parent, borderRelief='raised', text=' ', justify='left', font=None, sticky='ew', docKey=None, tipText=None, *args, **kw): Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=docKey, tipText=tipText) self.label.grid() self.canvasL = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.canvasR = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.bind('<Configure>', self.resize) def setText(self, text): self.label.set(text) self.resize() def resize(self, event=None): if event: w = event.width h = event.height else: w = int(self.winfo_width()) h = int(self.winfo_height()) self.after_idle(lambda: self.draw(w, h)) def draw(self, w, h): bw = int(self.label.winfo_height()) pad = bw / 2 h2 = h - (2 * bw) textWidth = int(self.label.winfo_reqwidth()) if self.justify == 'left': textLeft = (3 * pad) + (0.05 * w) textRight = min(w, textLeft + textWidth) elif self.justify == 'right': textRight = (3 * pad) + (0.05 * w) textLeft = w - (textWidth + textRight) else: textLeft = (w / 2) - (textWidth / 2) textRight = textLeft + textWidth c1 = self.canvas1 c1coords = c1.coords c1.place(x=0, y=0, anchor='nw', width=w, height=bw) self.label.place(x=textLeft, y=0, anchor='nw') e1, e2, e3 = self.canvasL c1coords(e1, pad, pad, textLeft - pad + 3, pad + 3) c1coords(e2, pad + 1, pad + 1, textLeft - pad + 3, pad + 3) c1coords(e3, pad + 1, pad + 1, textLeft - pad + 2, pad + 2) e1, e2, e3 = self.canvasR c1coords(e1, textRight + pad, pad, w - pad + 3, pad + 3) c1coords(e2, textRight + pad + 1, pad + 1, w - pad + 3, pad + 3) c1coords(e3, textRight + pad + 1, pad + 1, w - pad + 2, pad + 2)