Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Set a Gradient as a background?
-
Is there a way to 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