Welcome, guest | Sign In | My Account | Store | Cart
# 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()

Diff to Previous Revision

--- revision 3 2017-03-11 02:35:37
+++ revision 4 2017-03-11 03:43:56
@@ -41,15 +41,14 @@
         
else:
             
raise ValueError()
     
except:
-        raise ValueError("Invalid value %r provided for rgb color."
-                         % str_rgb)
+        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):
-        Canvas.__init__(self, master)
+    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
@@ -72,32 +71,42 @@
                 
raise ValueError("height can not be None")
             
             
self.configure(height=height)
-            width = self.winfo_screenwidth()
+            
+            if width is not None:
+                self.configure(width=width)
 
-            image = Image.new("RGB", (width, height), "#FFFFFF")
+            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(height * i)/steps)
-                y1 = int(float(height * (i+1))/steps)
+                y0 = int(float(img_height * i)/steps)
+                y1 = int(float(img_height * (i+1))/steps)
 
-                draw.rectangle((0, y0, width, y1), fill=(int(r),int(g),int(b)))
+                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)
-            height = self.winfo_screenheight()
             
-            image= Image.new("RGB", (width, height), "#FFFFFF")
+            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(width * i)/steps)
-                x1 = int(float(width * (i+1))/steps)
+                x0 = int(float(img_width * i)/steps)
+                x1 = int(float(img_width * (i+1))/steps)
 
-                draw.rectangle((x0, 0, x1, height), fill=(int(r),int(g),int(b)))
+                draw.rectangle((x0, 0, x1, img_height), fill=(int(r),int(g),int(b)))
         
         
self._gradient_photoimage = ImageTk.PhotoImage(image)
 

History