I am currently trying to implement a custom widget that can have two colors in its' text. It almost works but I have two questions, the first one is: why is there a gap between the green and red BoxLayout div (blackbar in the attached image)? The second is how can I make the split labels to have a width of one div instead of two? I tried many things but nothing worked so far. Any suggestions/ideas are very appreciated! Thanks in advance
Visualisation of my problem. Image
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
<Split>:
orientation:"vertical"
NormalLabel
NormalLabel
BoxLayout:
orientation:"vertical"
size_hint:1,None
TopHalfLabel
BottomHalfLabel
NormalLabel
NormalLabel
<TopHalfLabel>:
size_hint:1,None
markup:True
text:"[color=#FF0000]How can I do this?[/color]"
font_size:30
height: self.texture_size[1]
canvas.before:
Color:
rgba: 1, 0, 0, 0.3 # Border color (red in this example)
Rectangle:
pos: self.pos
size: self.size
<BottomHalfLabel>:
size_hint:1,None
markup:True
text:"[color=#FFFF00]How can I do this?[/color]"
font_size:30
height: self.texture_size[1]
canvas.before:
Color:
rgba: 0, 0, 1, 0.3 # Border color (red in this example)
Rectangle:
pos: self.pos
size: self.size
<NormalLabel>:
size_hint:1,None
markup:True
text:"[color=#FFFF00]How can I do this?[/color]"
font_size:30
height: self.texture_size[1]#
canvas.before:
Color:
rgba: 0, 1, 0, 0.3 # Border color (red in this example)
Rectangle:
pos: self.pos
size: self.size
''')
class NormalLabel(Label):
pass
class TopHalfLabel(Label):
def on_texture_size(self, instance, value):
#self.texture = self.texture.get_region(0, self.texture.height/2, self.texture.width, self.texture.height/2)
self.texture = self.texture.get_region(0, self.texture.height/2, self.texture.width, self.texture.height)
class BottomHalfLabel(Label):
def on_texture_size(self, instance, value):
#self.texture = self.texture.get_region(0, 0, self.texture.width, self.texture.height/2)
self.texture = self.texture.get_region(0, -self.texture.height/2, self.texture.width, self.texture.height)
class Split(BoxLayout):
pass
class MyApp(App):
def build(self):
return Split()
if __name__ == '__main__':
MyApp().run()
You can redefine the style of a Widget
by prefixing its kv
rule with a -
. See the documentation. So, I modified your kv
rules like this:
<-TopHalfLabel>:
size_hint:1,None
markup:True
text:"[color=#FF0000]How can I do this?[/color]"
font_size:30
height: self.texture_size[1]/2
canvas.before:
Color:
rgba: 1, 0, 0, 0.3 # Border color (red in this example)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
texture: self.new_texture
size: self.texture_size[0], self.texture_size[1]/2
pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1]/4)
<-BottomHalfLabel>:
size_hint:1,None
markup:True
text:"[color=#FFFF00]How can I do this?[/color]"
font_size:30
height: self.texture_size[1]/2
canvas.before:
Color:
rgba: 0, 0, 1, 0.3 # Border color (red in this example)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
texture: self.new_texture
size: self.texture_size[0], self.texture_size[1]/2
pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1]/4)
The main changes are setting the height
to half the texture height and the addition of the canvas
section, which is based on the default kv
for a Label
, but uses a new_texture
property that is defined by modified classes:
class TopHalfLabel(Label):
new_texture = ObjectProperty(None)
def on_texture_size(self, instance, value):
# self.texture = self.texture.get_region(0, self.texture.height/2, self.texture.width, self.texture.height/2)
self.new_texture = self.texture.get_region(0, self.texture.height / 2, self.texture.width, self.texture.height/2)
class BottomHalfLabel(Label):
new_texture = ObjectProperty(None)
def on_texture_size(self, instance, value):
# self.texture = self.texture.get_region(0, 0, self.texture.width, self.texture.height/2)
self.new_texture = self.texture.get_region(0, 0, self.texture.width, self.texture.height/2)
I also added a height: self.minimum_height
in the containing BoxLayout
:
<Split>:
orientation:"vertical"
NormalLabel
NormalLabel
BoxLayout:
orientation:"vertical"
size_hint:1,None
height: self.minimum_height
TopHalfLabel
BottomHalfLabel
NormalLabel
NormalLabel
I think this does what you want.