包装Kivy标签的文本

Geo*_*Bou 1 python kivy

所以我正在使用Kivy GUI编写程序,我真的不想使用.kv文件,而是将它全部写在python文件中.问题是在MainScreen类里面我想添加一些标签,但我不能根据窗口大小的变化使它们的文本换行.当我尝试时self.size我只得到100x100.我已经尝试了Kivy教程书中的所有建议,但没有任何效果.我知道我可以使文本多行使用\n或设置标准标签大小,但这不是一个真正的解决方案.我需要标签大小和文本来跟踪整个窗口的更改和要包装的文本.

我简化了程序,只关注这个问题.

这是代码:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color


class MainScreen(FloatLayout):
    """MAIN WINDOW CLASS"""

    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

        with self.canvas.before:
            Color(0.988, 0.725, 0.074, 1, mode='rgba')
            self.rect = Rectangle(pos=self.pos, size=self.size)
        self.bind(size=self.update_rect)


        #TITLE LABEL
        self.add_widget(Label(text="A very Long Sentence that needs to be wrapped.",
                              bold = True,
                              font_size="20sp",
                              pos_hint={'center_x': 0.5, 'center_y': .85},
                              size_hint=(None, None),
                              halign="center",
                              color=(0.055, 0.235, 0.541, 1)))

    def update_rect(self, *args):
        """FUNCTION TO UPDATE THE RECATANGLE OF CANVAS TO FIT THE WHOLE SCREEN OF MAINSCREEN ALWAYS"""
        self.rect.pos = self.pos
        self.rect.size = self.size

class main(App):
    """BUILDING THE APP"""
    def build(self):
        return MainScreen()

if __name__ == "__main__":
    main().run()
Run Code Online (Sandbox Code Playgroud)

谢谢.

Tsh*_*man 8

首先,让我告诉你,你将使你的生活变得比它应该更难,kv不难学,并且它允许kivy为你做更多的繁重工作.

在kv,做类似的事情

Label:
    text: 'blah blah ' * 1000
    text_size: self.width, None
    size_hint: 1, None
    height: self.texture_size[1]
Run Code Online (Sandbox Code Playgroud)

通常会做的伎俩,因为小部件使用其容器的整个宽度,并且text_size被绑定到它的宽度,每当这个宽度改变时,纹理将被重新计算,并且小部件的高度将自动适应高度纹理.

现在,没有kv做同样的事情.

  label = Label(text='blah blah '* 1000, size_hint=(1, None))
  label.bind(
      width=lambda *x: label.setter('text_size')(label, (label.width, None),
      texture_size=lambda *x: label.setter('height')(label, label.texture_size[1]))
Run Code Online (Sandbox Code Playgroud)

也就是说,你需要明确告诉kivy它必须对标签的各种属性的变化作出反应,并重新计算其他属性的值,而使用kv时,它会自动检测到某些值依赖于其他值,并且会知道它需要自己绑定它们.

setter 是一个实用函数,它允许你避免在简单的情况下定义setter函数,如果没有它,在这里,你必须为每个绑定定义一个函数,并执行类似"self.text_size = self.width,None "在他们中间,因为lambda不允许分配.

kv存在的原因之一是,它允许自己处理代码中的表达式,并检测依赖关系,如果你在python中完成所有操作,kivy就无法检测到这种依赖关系,因为python本身并不关心关于他们,并没有告诉kivy他们.

现在,如果你想告诉我们你为什么要避免kv,请做,但我很确定这些原因来自于缺乏了解kv而不是真正的问题.


Fer*_*erd 8

我会利用美妙的 OOP。

你可以像这样创建类:

class WrappedLabel(Label):
    # Based on Tshirtman's answer
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(
            width=lambda *x:
            self.setter('text_size')(self, (self.width, None)),
            texture_size=lambda *x: self.setter('height')(self, self.texture_size[1]))
Run Code Online (Sandbox Code Playgroud)

然后在您想要“包装行为”的代码的任何部分使用您的类。例子:

my_label = WrappedLabel(text="A very L" + "o"*200 + "ng Sentence that needs to be wrapped.",
                        bold=True,
                        font_size="20sp")
Run Code Online (Sandbox Code Playgroud)


Geo*_*Bou 1

因此,在对我的问题进行了很多思考并尝试了不同的方法之后,我最终得到了一个正确的“只是 python”解决方案。

首先,我的答案基于 1)官方 Kivy 教程建议,2)画布方法的通常操作以及 3)对变量范围的仔细处理。

所以Label的设置和Kivy教程书中建议的类似。需要有一个函数来更新标签位置及其文本大小(此处setting_function)以与标签大小绑定。我还将标签分配给了一个变量,以便稍后可以轻松引用它。

经过所有这些更改后,我的代码如下所示:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color


class MainScreen(FloatLayout, Label):
    """MAIN WINDOW CLASS"""

    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

        with self.canvas.before:
            Color(0.988, 0.725, 0.074, 1, mode='rgba')
            self.rect = Rectangle(pos=self.pos, size=self.size)
        self.bind(size=self.update_rect)

        #TITLE LABEL
        self.titlos = Label(text="A very Long Sentence that needs to be wrapped.",
                              bold = True,
                              text_size=(None,None),
                              font_size="20sp",
                              pos_hint={'center_x': 0.5, 'center_y': .85},
                              size_hint_y=None,
                              size = self.size,
                              height=self.texture_size[1],
                              halign="center",
                              valign = "middle",
                              color=(0.055, 0.235, 0.541, 1))

        self.add_widget(self.titlos)
        self.titlos.bind(size=self.setting_function)

    def setting_function(self, *args):
        """FUNCTION TO UPDATE THE LABEL TO ADJUST ITSELF ACCORDING TO SCREEN SIZE CHANGES"""
        self.titlos.pos_hint = {'center_x': 0.5, 'center_y': .85}
        self.titlos.text_size=self.size

    def update_rect(self, *args):
        """FUNCTION TO UPDATE THE RECATANGLE OF CANVAS TO FIT THE WHOLE SCREEN OF MAINSCREEN ALWAYS"""
        self.rect.pos = self.pos
        self.rect.size = self.size


class main(App):
    """BUILDING THE APP"""
    def build(self):
        return MainScreen()

if __name__ == "__main__":
    main().run()
Run Code Online (Sandbox Code Playgroud)

上面的代码确实满足我在问题中设置的要求。很容易将其用于您自己的项目。只需注意变量的范围并使用大量打印消息进行检查即可。

最后,我想仅使用 Python 来解决这个问题(而不仅仅是使用 kivy 语言来处理这些问题就像小菜一碟)的原因是我想要在运行时动态更改的变量,这些变量用作标签参数。而且我也必须找出答案,因为我很固执。

谢谢。