Last active
August 18, 2026 23:58
-
-
Save gottadiveintopython/51c0c8d3164bbc75f441eb3468c9a943 to your computer and use it in GitHub Desktop.
Kivy Label that doesn't waste texture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ''' | |
| 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