Frame with linear gradient using PIL.
It's also possible to make the same trick using tkinter PhotoImage.
http://stackoverflow.com/questions/10417524/why-is-photoimage-put-slow
But PIL is more efficient:
https://groups.google.com/forum/#!topic/comp.lang.python/nQ6YO-dTz10
Possible values for orient are: VERTICAL, HORIZONTAL. If orient is "vertical", then width is mandatory. If orient is "horizontal", then height is mandatory. If steps is None, then the gradient is composed of adjacent lines.
One possible practical application of gradient frames are tool bars. Gradient guives a visual clue of when an area starts and when an area finish.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | # Author: Miguel Martinez Lopez
#
# Uncomment the next line to see my email
# print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
#
#
# PIL is more efficient manipulating directly pixels than PhotoImage. See this discussion:
# https://groups.google.com/forum/#!topic/comp.lang.python/nQ6YO-dTz10
#
# To install PIL on windows for Python 3, read this:
# http://stackoverflow.com/questions/7407185/pil-for-python-3-2-on-windows-or-alternatives
#
# To install ImageTk for Python 2.7 on ubuntu do:
# sudo apt-get install python-imaging-tk
# and for Python 3:
# sudo apt-get install python3-pil.imagetk
#
try:
from Tkinter import Canvas
from Tkconstants import *
except ImportError:
from tkinter import Canvas
from tkinter.constants import *
from PIL import Image, ImageDraw, ImageTk
# Python 2/3 compatibility
try:
basestring
except NameError:
basestring = str
def hex2rgb(str_rgb):
try:
rgb = str_rgb[1:]
if len(rgb) == 6:
r, g, b = rgb[0:2], rgb[2:4], rgb[4:6]
elif len(rgb) == 3:
r, g, b = rgb[0] * 2, rgb[1] * 2, rgb[2] * 2
else:
raise ValueError()
except:
raise ValueError("Invalid value %r provided for rgb color."% str_rgb)
return tuple(int(v, 16) for v in (r, g, b))
class GradientFrame(Canvas):
def __init__(self, master, from_color, to_color, width=None, height=None, orient=HORIZONTAL, steps=None, **kwargs):
Canvas.__init__(self, master, **kwargs)
if steps is None:
if orient == HORIZONTAL:
steps = height
else:
steps = width
if isinstance(from_color, basestring):
from_color = hex2rgb(from_color)
if isinstance(to_color, basestring):
to_color = hex2rgb(to_color)
r,g,b = from_color
dr = float(to_color[0] - r)/steps
dg = float(to_color[1] - g)/steps
db = float(to_color[2] - b)/steps
if orient == HORIZONTAL:
if height is None:
raise ValueError("height can not be None")
self.configure(height=height)
if width is not None:
self.configure(width=width)
img_height = height
img_width = self.winfo_screenwidth()
image = Image.new("RGB", (img_width, img_height), "#FFFFFF")
draw = ImageDraw.Draw(image)
for i in range(steps):
r,g,b = r+dr, g+dg, b+db
y0 = int(float(img_height * i)/steps)
y1 = int(float(img_height * (i+1))/steps)
draw.rectangle((0, y0, img_width, y1), fill=(int(r),int(g),int(b)))
else:
if width is None:
raise ValueError("width can not be None")
self.configure(width=width)
if height is not None:
self.configure(height=height)
img_height = self.winfo_screenheight()
img_width = width
image = Image.new("RGB", (img_width, img_height), "#FFFFFF")
draw = ImageDraw.Draw(image)
for i in range(steps):
r,g,b = r+dr, g+dg, b+db
x0 = int(float(img_width * i)/steps)
x1 = int(float(img_width * (i+1))/steps)
draw.rectangle((x0, 0, x1, img_height), fill=(int(r),int(g),int(b)))
self._gradient_photoimage = ImageTk.PhotoImage(image)
self.create_image(0, 0, anchor=NW, image=self._gradient_photoimage)
if __name__ == "__main__":
try:
from Tkinter import Tk, Label
except ImportError:
from tkinter import Tk, Label
root = Tk()
Label(root, text="Gradient 1:").pack(anchor=W)
GradientFrame(root, from_color="#000000", to_color="#E74C3C", height=100).pack(fill=X)
Label(root, text="Gradient 2 (GTK gradient):").pack(anchor=W, pady=(20,0))
GradientFrame(root, from_color="#FCFCFC", to_color="#E2E2E2", height=30).pack(fill=X, pady=(0,10))
root.mainloop()
|