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

Kivy中如何准确获取TextInput按实际显示折行划分的每行文本

Kivy TextInput 软折行文本提取可靠方案

别直接用_lines属性拿结果,这是TextInput的内部中间变量,存的是混了硬换行、没走完渲染校验的临时数据,碰到组件刚调整尺寸、文本刚更新的时序,行数统计错误、内容串行都是常事。texture_size属性TextInput确实支持,但没必要靠这个自己算折行——组件本身渲染的时候已经算过一遍准确的折行位置了,直接拿渲染层的结果就行,比自己重写折行逻辑靠谱得多。

具体实现

首先卡准取数时机:别在组件初始化的时候读,那会尺寸、字体渲染都没跑完,拿什么值都不准。给on_size、on_text事件绑回调,用Clock.schedule_once延迟1帧等渲染走完再取值,就不会拿到中间状态的错误数据。
取值直接读TextInput内部负责文本渲染的_label实例的lines属性,这个列表里存的就是实打实画到屏幕上的每行内容,和用户看到的软折效果完全一致。
可直接复用的代码示例:

from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.clock import Clock

class WrappedTextInput(TextInput):
    def get_visible_wrapped_lines(self):
        # 渲染实例未初始化时直接返回空
        if not getattr(self, '_label', None):
            return []
        # 过滤掉渲染预留的尾部空行占位
        return [line for line in self._label.lines if line]

    def on_size(self, *args):
        # 尺寸变更后等1帧渲染完成再触发计算
        Clock.schedule_once(lambda dt: print(self.get_visible_wrapped_lines()), 0)

    def on_text(self, *args):
        Clock.schedule_once(lambda dt: print(self.get_visible_wrapped_lines()), 0)

class TestWrapApp(App):
    def build(self):
        ti = WrappedTextInput(text="Hello I came from the earth and my name is")
        return ti

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

效果说明

  • 组件宽度足够折为2行时,输出为["Hello I came from the", "earth and my name is"]
  • 拉窄组件折为3行时,输出为["Hello I came", "from the earth", "and my name is"]
  • 碰到硬换行、中英文混排、特殊字符的场景,返回结果和实际显示完全匹配,不会出现_lines偶发的错位问题。

别自己手动算文本宽度拆行,不同操作系统、不同字体的字宽、字间距渲染有细微差异,自己算出来的折行位置总会和实际显示差几个像素,凑不对位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:36:28