Звучит как забавная головоломка. Итак, вот что я придумал:
from kivy.lang import Builder
from kivy.graphics.texture import Texture
from kivy.properties import ObjectProperty, ListProperty
from kivy.uix.label import Label
class LabelGradient(Label):
gradient = ObjectProperty(None)
bg_color = ListProperty([0, 0, 0, 255])
def __init__(self, **kwargs):
super(LabelGradient, self).__init__(**kwargs)
# bind to texture to trigger use of gradient
self.bind(texture=self.fix_texture)
def fix_texture(self, instance, texture):
if self.gradient is None:
return
# unbind, so we don't loop
self.unbind(texture=self.fix_texture)
# The normal Label texture is transparent except for the text itself
# This code changes the texture to make the text transparent, and everything else
# gets set to self.bg_color (a property of LabelGradient)
pixels = list(self.texture.pixels)
for index in range(3, len(pixels)-4, 4):
if pixels[index] == 0:
# change transparent pixels to the bg_color
pixels[index-3:index+1] = self.bg_color
else:
# make the text itself transparent
pixels[index] = 0
# create a new texture, blit the new pixels, and apply the new texture
new_texture = Texture.create(size=self.texture.size, colorfmt='rgba')
new_texture.blit_buffer(bytes(pixels), colorfmt='rgba', bufferfmt='ubyte')
new_texture.flip_vertical()
self.texture = new_texture
Builder.load_string('''
<LabelGradient>:
canvas.before:
# draw the gradient below the normal Label Texture
Color:
rgba: 1,1,1,1
Rectangle:
texture: self.gradient
size: self.texture_size
pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)
''')
if __name__ == '__main__':
from kivy.app import App
from kivy.lang import Builder
class LabelGradientApp(App):
grad = ObjectProperty(None)
def build(self):
# create a 64x64 texture, defaults to rgba / ubyte
self.grad = Texture.create(size=(64, 64))
# create 64x64 rgb tab, and fill with values from 0 to 255
# we'll have a gradient from black to white
size = 64 * 64 * 3
buf = bytes([int(x * 255 / size) for x in range(size)])
# then blit the buffer
self.grad.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
return theRoot
app = LabelGradientApp()
theRoot = Builder.load_string('''
FloatLayout:
LabelGradient:
text: 'Abba Dabba Doo'
font_size: 30
gradient: app.grad
''')
app.run()
Мой подход - сделать текст прозрачным и нарисовать градиент позади текста. Нормальный Texture
, созданный Label
, прозрачен, за исключением фактического текста.
Приведенный выше LabelGradient
расширяет Label
и dr aws градиент с использованием правила <LabelGradient>
в kv
. Метод fix_texture()
связан со свойством texture
Label
, поэтому он вызывается, как только создается Texture
. Метод fix_texture()
делает фактический текст прозрачным и устанавливает для остальной части Texture
значение bg_color
.