Kivy text markup printing its own syntax

痞子三分冷 提交于 2019-12-24 15:40:06

问题


I was testing out Kivy's markup feature. The basic outline of my test program is there are 4 labels and a button and if the button is pressed, it changes the color of the first letter of label's text. Now, the problem is when I press the button for the first time, it changes the color of first letter of all the label's text BUT from the second press onwards, it starts adding the markup syntax in the reverse manner at the beginning of the text. This is the program:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
import string

Builder.load_string(
'''
<CLabel@Label>:
    markup: True

<box>:
    orientation: 'vertical'

    Button:
        text: 'press'
        on_press: app.change()


    CLabel:
        id: a
        text: 'abcd'

    CLabel:
        id: b
        text: 'efgh'

    CLabel:
        id: c
        text: 'ijkl'

    CLabel:
        id: d
        text: 'mnop'
'''
)

class box(BoxLayout):
    pass

class main(App):
    def change(self):
        for lol in string.lowercase[:4]:
            self.root.ids[lol].text = '[color=#E5D209]{}[/color]{}'.format(self.root.ids[lol].text[0], self.root.ids[lol].text[1:])

    def build(self):
        return box()

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

This is the output after the first press:

This is the output after the second press:

This is the output after the third press:

I hope you get the problem now. The markup syntax at the beginning of the text keeps on increasing with the number of times the button is pressed.

I thought maybe it was the loop's fault. So I removed the loop and tested with only the first widget. Same problem.

Now here's the catch- when I change the color by changing the contents of the change function like this:

def change(self):
    self.root.ids.a.text = '[color=#E5D209]a[/color]bcd'
    self.root.ids.b.text = '[color=#E5D209]e[/color]fgh'
    self.root.ids.c.text = '[color=#E5D209]i[/color]jkl'
    self.root.ids.d.text = '[color=#E5D209]m[/color]nop'

It works perfectly fine. But by doing this method, I'll have to copy paste a lot of lines. This was just a snippet of what I'm working on. The real project I'm working on has more than 15 labels and copy pasting for each and every label is tiresome. It'd be much better if it is done by a loop. It makes work short and precise.

After this, out of frustration I tried with get_color_from_hex method by this code:

self.root.ids[lol].text[0] = self.root.ids[lol].text[0].get_color_from_hex('#E5D209')

But I ended up getting an error message saying:

AttributeError: 'str' object has no attribute 'color'

I'd be really glad if someone came with a way to change the color of first letter of the text of god knows how many labels. :'(


回答1:


The markup is part of the string stored in text. So the second time you run the loop, indeed the first character ([) gets inserted in between the markup tags, messing up the parsing.

What you want to do could be achieved by storing the raw text in another StringProperty, let's call it _hidden_text. Then, in the loop, you can set

self.root.ids[lol].text = '[color=#E5D209]{}[/color]{}'.format(self.root.ids[lol]._hidden_text[0], self.root.ids[lol]._hidden_text[1:])

In this way you avoid reusing the added markup. Of course you may want to set up bindings for making the assignment _hidden_texttext automatic.

Edit:

Add this class definition:

class CLabel(Label):
    hidden_text = StringProperty('')

then change the kv style for CLabel to

<CLabel>:
    markup: True
    text: self.hidden_text

and each use of CLabel should look like

CLabel:
    id: a
    hidden_text: 'abcd'


来源:https://stackoverflow.com/questions/36772411/kivy-text-markup-printing-its-own-syntax

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!