Skip to content

Instantly share code, notes, and snippets.

@gottadiveintopython
Last active August 18, 2026 23:58
Show Gist options
  • Select an option

  • Save gottadiveintopython/51c0c8d3164bbc75f441eb3468c9a943 to your computer and use it in GitHub Desktop.

Select an option

Save gottadiveintopython/51c0c8d3164bbc75f441eb3468c9a943 to your computer and use it in GitHub Desktop.
Kivy Label that doesn't waste texture
'''
KivyのLabelはpaddingを設定するとその分だけtextureを大きくしてしまうのでそれへの対策。
'''
__all__ = ("EcoLabel", )
from kivy.properties import NumericProperty, ReferenceListProperty, OptionProperty
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.label import Label
Builder.load_string("""
<-EcoLabel>:
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
group: "EcoLabel_rectangle"
texture: self.texture
size: self.texture_size
""")
class EcoLabel(Label):
minimum_width = NumericProperty()
minimum_height = NumericProperty()
minimum_size = ReferenceListProperty(minimum_width, minimum_height)
halign = OptionProperty("center", options=("left", "center", "right", ))
valign = OptionProperty("center", options=("top", "center", "bottom", ))
def on_kv_post(self, *args, **kwargs):
super().on_kv_post(*args, **kwargs)
self._rectangle_inst = self.canvas.get_group("EcoLabel_rectangle")[0]
dont_make_the_texture_bigger_just_for_padding(self)
dont_update_the_texture_when_halign_or_valign_changes(self)
t = Clock.schedule_once(self._update_minimum_size, -1)
self.bind(texture_size=t, padding=t)
t = Clock.schedule_once(self._update_texture_position, -1)
self.bind(texture_size=t, size=t, pos=t, padding=t, halign=t, valign=t)
def _update_minimum_size(self, dt):
w, h = self.texture_size
left, top, right, bottom = self.padding
self.minimum_width = w + left + right
self.minimum_height = h + top + bottom
def _update_texture_position(self, *args):
x, y = self.pos
w, h = self.size
tw, th = self.texture_size
left, top, right, bottom = self.padding
match self.halign:
case "center":
tx = x + (w - tw) / 2.
case "left":
tx = x + left
case _:
tx = x + w - tw - right
match self.valign:
case "center":
ty = y + (h - th) / 2.
case "bottom":
ty = y + bottom
case _:
ty = y + h - th - top
self._rectangle_inst.pos = (tx, ty)
def dont_make_the_texture_bigger_just_for_padding(label: Label):
label._label.options["padding"] = (0, ) * 4
t = label._trigger_texture_update
for name in ("padding_x", "padding_y", "padding", ):
label.funbind(name, t, name)
t()
def dont_update_the_texture_when_halign_or_valign_changes(label: Label):
label._label.options.update(halign="center", valign="center")
t = label._trigger_texture_update
for name in ("halign", "valign", ):
label.funbind(name, t, name)
t()
def test():
from textwrap import dedent
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.app import App
class TestApp(App):
def build(self):
Clock.schedule_interval(self.print_texture_size, 3)
return Builder.load_string(dedent("""
BoxLayout:
orientation: "vertical"
padding: 20
spacing: 20
Label:
id: label
text: "XXX"
halign: "right"
padding: (20, 20)
EcoLabel:
id: ecolabel
text: "XXX"
halign: "right"
padding: (20, 20)
"""))
def print_texture_size(self, dt):
ids = self.root.ids
print("")
print("Label texture size:", ids.label.texture_size)
print("EcoLabel texture size:", ids.ecolabel.texture_size)
TestApp().run()
if __name__ == "__main__":
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment