Kivy: Load a text from a file in a label

1

I want to load a text from a file in a label. My code in python is:

# config
from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'system')

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

Builder.load_file('design.kv')

class MyWidget(BoxLayout):
    def __init__(self):
        super(MyWidget, self).__init__()

    def showtext(self):
        with open("Prueba.txt","r") as f:
            filetext = f.read()
            #self.ids['label1'].text = filetext


class myApp(App):
    def build(self):
        return MyWidget()
    def on_pause(self): 
        return True
    def on_resume(self): 
        pass


if __name__ in ('__main__', '__android__'): 
    myApp().run()

The design.kv file is:

<MyWidget>:
    BoxLayout:
        Label:
            id: label1
            text: root.showtext()

I get an error: ValueError: None is not allowed for Label.text

It seems that since I have defined the function showtext as def showtext(self) I have to put something where "self" goes in the file design.kv, then I put "label1" keeping the file design.kv like this:

<MyWidget>:
    BoxLayout:
        Label:
            id: label1
            text: root.showtext(label1)

Then he gives me the following error: TypeError: showtext () takes 1 positional argument but 2 were given

I do not understand, he says that I have given him two arguments, when I have only given one, label1. Could someone tell me what to put or change to load text from a txt to label?

Thank you very much in advance.

    
asked by Mr. Baldan 16.04.2017 в 21:55
source

1 answer

2

The problem is told by the error itself, you are trying to pass None as text for Label . The question is, where does the None come from?

In your .kv file you define that the text is the function showtext , then the method is called to get the text. The problem is that the showtext method returns nothing, if you do not define a return to a function / method in Python using return it returns None by default.

In order for this form to work, you must have the method return the text:

def showtext(self):
    with open("Prueba.txt","r") as f:
        return(f.read())

The first kv file you add is the correct one:

<MyWidget>:
    Label:
        id: label1
        text: root.showtext()

Regarding your doubt as to why it says that you are passing two arguments when you spend only one when doing text: root.showtext(label1) . This is because the parameter self is passed automatically, although when creating the method it must be explicitly defined. That is, although you call doing:

 root.showtext(label1)

Internally the call symbolically would be something like:

showtext(self, label1)

self is actually a convention recommended in the PEP, it can be called as we want, it is not a reserved word, although calling it self makes life easier for others who read our code. In reality it is nothing more than a reference to the very instance of the class, a reference to itself, hence the name 'self'. Indicates that this method or attribute belongs to the class.

Another option to do the same would be to not define the text in the .kv and use the text attribute of the label to pass the text from the Python code itself. The function in this case can be called by another widget, like a button, or call it from the constructor itself:

from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'system')

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import StringProperty


Builder.load_file('design2.kv')

class MyWidget(BoxLayout):
    def __init__(self):
        super(MyWidget, self).__init__()
        self.showtext() #Llamamos al método desde el constructor

    def showtext(self):
        with open("Prueba.txt","r") as f:
            self.ids['Label1'].text = f.read()


class myApp(App):
    def build(self):
        return MyWidget()
    def on_pause(self):
        return True
    def on_resume(self):
        pass


if __name__ in ('__main__', '__android__'):
    myApp().run()

in this case the .kv would be simply:

<MyWidget>:
    Label:
        id: Label1
    
answered by 16.04.2017 / 22:52
source