Search code examples
pythonkivykivy-language

AttributeError: '' object has no attribute 'ids'


I got an error from this code, I am trying to change the color of the button when pressed.

The code:

Builder.load_string('''
<FileBrowserApp>:
    Button:
        id: 'b1'
        text: 'Select Files'
        pos_hint: {'x':0, 'y': 0}
        size_hint: (1, 0.1)
        on_press: self.do_select
        on_press: self.background_color=[0,0,255,1]
        on_release: self.background_color=[192,192,19,1]   
''')


class FileBrowserApp(App):
    def build(self):
        try:
            if(self.out):
            self.root.remove_widget(self.out)
        except:
            pass

        self.root = FloatLayout()
        self.bn = BoxLayout(orientation="horizontal")

        button1 = self.ids['b1']
    
        self.bn.add_widget(button1)

        self.out = BoxLayout(orientation="vertical")

        self.root.add_widget(self.out)
        self.root.add_widget(self.bn)
        
        return self.root

The error:

Traceback (most recent call last):
File "kk.py", line 120, in <module>
 app.run()
File "/usr/lib/python3/dist-packages/kivy/app.py", line 800, in run
 root = self.build()
File "kk.py", line 47, in build
 button1 = self.ids['b1']
AttributeError: 'FileBrowserApp' object has no attribute 'ids'

is that Builder.load_string() allows more than one class to create a kv language

How to resolve this error?


Solution

  • You cannot add a Button to the FileBrowserApp as you appear to attempt in your kv. Your construction is appropriate for adding a Button to a container (like a Layout), but an App is not a container. If you want to define a Button in your kv you can do it by defining a new class that extends Button like this:

    class SelectFileButton(Button):
        pass
    

    Then create a rule for SelectFileButton in the kv:

    Builder.load_string('''
    <SelectFileButton>:
        text: 'Select Files'
        pos_hint: {'x':0, 'y': 0}
        size_hint: (1, 0.1)
        on_press: app.do_select()
        on_press: self.background_color=[0,0,255,1]
        on_release: self.background_color=[192,192,19,1]   
    ''')
    

    This rule defines how a SelectFileButton should be configured, and can then be used in the build() method:

    class FileBrowserApp(App):
        def build(self):
            try:
                if (self.out):
                    self.root.remove_widget(self.out)
            except:
                pass
    
            self.root = FloatLayout()
            self.bn = BoxLayout(orientation="horizontal")
    
            # create a Button based on the kv rule
            button1 = SelectFileButton()
            self.bn.add_widget(button1)
    
            self.out = BoxLayout(orientation="vertical")
    
            self.root.add_widget(self.out)
            self.root.add_widget(self.bn)
    
            return self.root
    
        def do_select(self):
            print('do select')
    

    That is one way to do it, but a better approach might be to create a rule in kv that describes how the entire root of the FileBrowserApp should be built. Then the build() method would simply be returning that root. Or, if you put that kv in a file named filebrowser.kv, you don't even need a build() method. See the documentation.