You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Python的Kivy框架中实现标签自适应文本尺寸

问题:动态创建标签并实现左对齐

我正基于从数据库获取的信息创建标签,希望在网格中实现左对齐。为此,我尝试让标签紧密包裹文本,以便在AnchorLayout中左对齐标签。由于标签文本及带标签的网格数量是动态的,我选择通过Python代码而非kv文件实现。我看过很多Kivy语言实现该功能的文档,但不知道如何用Python实现。调用tour_name_label.texture_size返回[0. 0],似乎无法访问该属性并将其设置为标签尺寸。我刚接触Kivy,对bind、getter和setter方法不太熟悉,该如何解决这个问题?


main.py

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from tour_grid import TourGrid
from kivy.core.window import Window
from kivy.core.text import LabelBase
import requests
import json

class MyToursScreen(Screen):
    pass


class Main(MDApp):
    acc_id = 0

    def build(self):
        # self.theme_cls.material_style = "M3"
        # self.theme_cls.theme_style = "Dark"
        Window.size = (360, 600)
        return Builder.load_file("main.kv")

    def on_start(self):
        # Sample tour data
        tour_data = [{'acc_id': 0, 'date_tour_created': '16-02-2024', 'name': 'Bike Tour Norway', 'starting_date': '13-06-2024', 'tour_id': 0}]
        # print(self.root.ids)
        
        # Populate tour grid on home screen
        tours_grid = self.root.ids["my_tours"].ids["tours_grid"]
        for tour in tour_data:
            T = TourGrid(tour_name=tour["name"], starting_date=tour["starting_date"])
            tours_grid.add_widget(T)


if __name__ == "__main__":
    Main().run()

tour_grid.py(问题所在文件)

from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.graphics import Color, Rectangle
import kivy.utils

class TourGrid(GridLayout):
    def __init__(self, **kwargs):
        self.cols = 1
        super(TourGrid, self).__init__() # Initialize GridLayout with kwargs

        with self.canvas.before:
            Color(rgb=kivy.utils.get_color_from_hex("#dddddd"))
            self.rect = Rectangle(size=self.size, pos=self.pos)

        self.bind(pos=self.update_rect, size=self.update_rect)
        
        # PROBLEM HERE, MADE INTO BUTTON TO CHECK DIMENSIONS
        # Top FloatLayout containing name of tour
        top = AnchorLayout(anchor_x="center", anchor_y="center")
        tour_name_label = Button(text=str(kwargs["tour_name"]), color=kivy.utils.get_color_from_hex("#000000"))

        # tour_name_label.bind(texture_size=tour_name_label.setter("size"))
        # print(tour_name_label.getter("texture_size"))
        # print(tour_name_label.setter("texture_size")())
        top.add_widget(tour_name_label)

        # Bottom FloatLayout containing starting date
        bottom = AnchorLayout(anchor_y="center")
        starting_date_label = Label(text="[color=000000]" + kwargs["starting_date"] + "[/color]", size_hint=[1, 0.3], pos_hint={"top": 1, "left": 1}, markup=True)
        bottom.add_widget(starting_date_label)

        self.add_widget(top)
        self.add_widget(bottom)

    def update_rect(self, *_):
        self.rect.pos = self.pos
        self.rect.size = self.size

main.kv

#:include kv/my_tours.kv

BoxLayout:
    ScreenManager:
        id: screen_manager
        
        MyToursScreen:
            id: my_tours
            name: "my_tours"

my_tours.kv

#:import utils kivy.utils

<MyToursScreen@Screen>:
    FloatLayout:
        # Top bar, profile image and name, notification and settings button
        GridLayout:
            rows: 1
            pos_hint: {"top": 1, "left": 1}
            size_hint: 1, 0.1
            
            canvas:
                Color: 
                    rgb: utils.get_color_from_hex("#25be55")
                Rectangle:
                    size: self.size
                    pos: self.pos
                    
        # Main grid with tours
        ScrollView:
            pos_hint: {"top": 0.9, "left": 1}
            size_hint: 1, 0.8

            GridLayout:
                id: tours_grid
                cols: 1
                size_hint_y: None
                height: self.minimum_height
                row_default_height: "70dp"
                row_force_default: True
                
                Label:
                    text: "Planned trips"
                    color: utils.get_color_from_hex("#000000")

        # Bottom bar, My Tours button
        GridLayout:
            rows: 1
            pos_hint: {"top": 0.1, "left": 1}
            size_hint: 1, 0.1

            canvas:
                Color: 
                    rgb: utils.get_color_from_hex("#25be55")
                Rectangle:
                    size: self.size
                    pos: self.pos

            Label:
                text: "My tours"
                bold: True           

解决方案

核心问题分析

texture_size返回[0,0]是因为标签还没完成布局渲染,此时文本纹理尚未生成。要实现标签紧密包裹文本并左对齐,需要正确绑定texture_size到标签尺寸,同时调整布局锚点和标签的size_hint。

修改后的tour_grid.py代码

from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
import kivy.utils

class TourGrid(GridLayout):
    def __init__(self, **kwargs):
        self.cols = 1
        # 将kwargs传入父类初始化,避免参数丢失
        super(TourGrid, self).__init__(**kwargs)

        with self.canvas.before:
            Color(rgb=kivy.utils.get_color_from_hex("#dddddd"))
            self.rect = Rectangle(size=self.size, pos=self.pos)

        self.bind(pos=self.update_rect, size=self.update_rect)
        
        # 顶部左对齐布局,添加左内边距避免文本贴边
        top = AnchorLayout(anchor_x="left", anchor_y="center", padding=(10, 0))
        tour_name_label = Label(
            text=str(kwargs["tour_name"]),
            color=kivy.utils.get_color_from_hex("#000000"),
            size_hint=(None, None)  # 取消自动尺寸适配,让标签仅包裹文本
        )
        # 绑定纹理尺寸到标签尺寸,渲染完成后自动调整
        tour_name_label.bind(texture_size=tour_name_label.setter("size"))
        top.add_widget(tour_name_label)

        # 底部左对齐布局,同样添加内边距
        bottom = AnchorLayout(anchor_x="left", anchor_y="center", padding=(10, 0))
        starting_date_label = Label(
            text="[color=000000]" + kwargs["starting_date"] + "[/color]",
            size_hint=(None, None),
            markup=True
        )
        starting_date_label.bind(texture_size=starting_date_label.setter("size"))
        bottom.add_widget(starting_date_label)

        self.add_widget(top)
        self.add_widget(bottom)

    def update_rect(self, *_):
        self.rect.pos = self.pos
        self.rect.size = self.size

关键修改说明

  1. size_hint=(None, None):必须设置该属性,否则Kivy会强制标签占满父布局空间,无法实现紧密包裹文本的效果。
  2. bind(texture_size=tour_name_label.setter("size")):该绑定会在文本纹理生成后,自动将纹理尺寸赋值给标签的size属性,确保标签刚好适配文本内容。
  3. anchor_x="left":调整AnchorLayout的锚点为左侧,配合padding参数让文本靠左显示且不贴边,提升视觉体验。

内容的提问来源于stack exchange,提问作者MKJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:32:05