Is there a way to set a gradient as a background?
Forum Archive
Set a Gradient as a background?
I think you need to use a custom View with a custom draw method for the background. Here's the code for ObjC, looks easy to convert to Python.
May be just draw a sequence of rectangles.
import ui
class MyView(ui.View):
def __init__(self, gradient, *args, **kwargs):
self.gradient = gradient
super().__init__(*args, **kwargs)
self.step_size = 3
def draw(self):
x,y,w,h = self.frame
((fr,fg,fb), (tr, tg, tb)) = gradient
num_steps = int(w/self.step_size)
for step in range(num_steps):
x = step*self.step_size
t = step/num_steps
path = ui.Path.rect(x,0,self.step_size,h)
ui.set_color((fr*(1-t)+tr*t, fg*(1-t)+tg*t, fb*(1-t)+tb*t))
path.fill()
path = ui.Path.rect(num_steps*self.step_size, 0, w-num_steps*self.step_size, h)
ui.set_color((tr,tg,tb))
path.fill()
w,h = 400,400
gradient = ((1,0,0) , (0,1,0))
v = MyView(gradient, frame=(0,0,w,h))
v.present('sheet')
@robertiii have a look at this. Pretty silly but still illustrative. If you search the forum for blur , there are also some nice effects that can be created like frosted glass. Sorry it was a long time ago, but some impressive effects. From memory it was using objc
Once I saw this thread I thought about a straight Python implementation. Since it was already done I extended @enceladus snippet into a universal Python gradient demo. I also included @Phuket2 radial takes (well sort of) and added a square gradient. A “Next” button at the bottom right of the window cycles the view between linear, radial and square gradient fills. I tried to stay as close as possible to the spirit of @enceladus code. It detects and uses the Pythonista UI, Kivy or Tkinter automatically. Therefore, it should work on any Python distribution unmodified. Come to think of it I think that they change the capitalization for Tkinter in version 3.xx. Change the name accordingly if you are using any python version higher than 2.xx This is nothing serious though just some “silly” (as @Phuket2 put it) coding for fun. Below is the script.
def getgui():
try:
import ui
platform = 'Pythonista'
gui = ui.View
except:
try:
from kivy.uix.floatlayout import FloatLayout
platform = 'Kivy'
gui = object
except:
from Tkinter import Tk
platform = 'Tk'
gui = object
return platform, gui
platform, gui = getgui()
if platform == 'Pythonista':
import ui
class MyView(gui):
def __init__(self, platform, gradient, *args, **kwargs):
self.gradient = gradient
self.step_size = 3
self.gradient_type = ['linear', 'radial', 'square']
self.current_fill = 0
self.grads = []
self.platform = platform
if self.platform == 'Pythonista':
ui.View.__init__(self, *args, **kwargs)
self.next_button = ui.Button(frame= \
(330, 360, 30, 60), title = 'Next')
self.next_button.background_color = (0.4,0.4,0.4)
self.next_button.action = self.next_fill
self.next_button.height = 30
self.next_button.width = 60
self.next_button.tint_color = 'white'
self.next_button.font = ('<system>', 12)
self.add_subview(self.next_button)
elif self.platform == 'Kivy':
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
self.root = FloatLayout()
self.frame = kwargs['frame']
self.next_button = Button( text = 'NEXT',
size_hint_y = None, size_hint_x = None,
height = 30, width = 60, font_size = 12, pos = (330, 10),
on_press = self.next_fill )
self.root.add_widget(self.next_button)
elif self.platform == 'Tk':
from Tkinter import Tk
from Tkinter import Canvas
from Tkinter import Frame
from Tkinter import Label
from Tkinter import NW
self.master = Tk()
self.root = Canvas(self.master, width=kwargs['frame'][2], \
height=kwargs['frame'][3])
self.root.pack()
self.frame = kwargs['frame']
contour = Frame(self.master, height=30, width=60)
contour.pack_propagate(0) # don't shrink
label = Label(contour, text='NEXT', fg='white', bg='#585858', \
height=30, width=60)
label.bind("<Button-1>", self.tk_button_down)
label.bind("<ButtonRelease-1>", self.tk_button_up)
label.pack()
label.config(font=('TkDefaultFont',12), padx=0,pady=0)
contour.place(x=330, y =360, anchor=NW)
def next_fill(self, sender):
self.current_fill += 1
if self.current_fill == 3:
self.current_fill = 0
if self.platform == 'Pythonista':
self.set_needs_display()
else:
self.draw()
def tk_button_down(self, event):
event.widget.config(bg='#00A5D4')
def tk_button_up(self, event):
event.widget.config(bg='#585858')
self.next_fill(self.tk_button_up)
def present_all(self, mode):
if self.platform == 'Pythonista':
self.present(mode)
if self.platform == 'Tk':
self.draw()
self.root.mainloop()
elif self.platform == 'Kivy':
from kivy.base import runTouchApp
from kivy.core.window import Window
Window.size = self.frame[2:4]
self.draw()
runTouchApp(self.root)
def draw(self):
x,y,w,h = self.frame
((fr,fg,fb), (tr, tg, tb)) = gradient
num_steps = int(w/self.step_size)
for step in range(num_steps):
x = step*self.step_size
t = step/(num_steps * 1.0)
if self.platform == 'Pythonista':
if self.gradient_type [self.current_fill] == 'linear':
path = ui.Path.rect(x,0,self.step_size,h)
elif self.gradient_type [self.current_fill] == 'radial':
if w - ((2 * step) * self.step_size) >= 0:
path = ui.Path.oval(x, x, w - 2*x, h-2*x)
elif self.gradient_type [self.current_fill] == 'square':
if w - ((2 * step) * self.step_size) >= 0:
path = ui.Path.rect(x,x,w - ((2*step) * \
(self.step_size)),h - (2*step)*self.step_size)
ui.set_color((fr*(1-t)+tr*t, fg*(1-t)+tg*t, fb*(1-t)+tb*t))
path.fill()
ui.set_color((fr*(1-t)+tr*t, fg*(1-t)+tg*t, fb*(1-t)+tb*t))
path.fill()
elif self.platform == 'Tk':
if step == 0:
self.root.create_rectangle( 0, 0, w, h, \
fill='black', outline='black')
cl = '#' + '%02x' % int((fr*(1-t)+tr*t) * 255) + \
'%02x' % int((fg*(1-t)+tg*t) * 255) + \
'%02x' % int((fb*(1-t)+tb*t) * 255)
if self.gradient_type [self.current_fill] == 'linear':
self.root.create_rectangle( x, 0, self.step_size + x, h, \
fill=cl, outline=cl)
elif self.gradient_type [self.current_fill] == 'radial':
if w - ((2 * step) * self.step_size) >= 0:
self.root.create_oval( x + self.step_size, x + \
self.step_size, w - ((2*step) * (self.step_size)) \
+ x, h - (2*step)*self.step_size + x, \
fill=cl, outline=cl)
elif self.gradient_type [self.current_fill] == 'square':
if w - ((2 * step) * self.step_size) >= 0:
self.root.create_rectangle( x, x, w - ((2*step) * \
(self.step_size)) + x, h - (2*step)*self.step_size \
+ x, fill=cl, outline=cl)
elif self.platform == 'Kivy':
if step == 0:
from kivy.graphics import Color
from kivy.graphics import Rectangle
self.grads.append ((fr*(1-t)+tr*t, fg*(1-t)+tg*t, \
fb*(1-t)+tb*t))
self.root.canvas.add(Color (fr*(1-t)+tr*t, fg*(1-t)+tg*t, \
fb*(1-t)+tb*t))
if self.gradient_type [self.current_fill] == 'linear':
self.root.canvas.add(Rectangle(pos = (x, 0), \
size = (self.step_size,h)))
elif self.gradient_type [self.current_fill] == 'radial':
if w - ((2 * step) * self.step_size) >= 0:
if step == 0:
from kivy.graphics import Line
self.root.canvas.add(Line(circle = (w/2, h/2, w - \
(2*step)*self.step_size), width = self.step_size))
elif self.gradient_type [self.current_fill] == 'square':
if w - ((2 * step) * self.step_size) >= 0:
self.root.canvas.add(Rectangle(pos = (x, x), size = \
(w - (2*step)*self.step_size, \
h - (2*step)*self.step_size)))
self.root.remove_widget(self.next_button)
self.root.add_widget(self.next_button)
w,h = 400,400
gradient = ((1,0,0) , (0,1,0))
v = MyView(platform,gradient, frame=(0,0,w,h))
v.present_all('sheet')
Since I intend to include “Tkinter” in future implementation of universal codes (refer to GAP in this forum) I went to investigate the 3.xx implementation of that module. They did take out the capitalization from “Tkinter”. Change the “Tkinter” block from “getgui()” to add one more exception (as shown below) and the script should run everywhere without modification.
try:
from Tkinter import Tk
platform = 'Tk'
gui = object
except:
import tkinter
import sys
sys.modules['Tkinter'] = tkinter
platform = 'Tk'
gui = object