kivykivy-languagenameerror

NameError: when instantiating a class in kv via a python statement in an event callback (e.g. on_parent)


I get the error "NameError: name 'MyButton' is not defined" when I try to make an instance of MyButton class directly. As a workaround, I extend this class in root widget (see MuButton2) and then there is no problem. Can someone explain why this is the case?

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from itertools import cycle

Builder.load_string('''

<MyButton>:

<MainWidget>:
    
    BoxLayout:

        on_parent:
            for i in range(2,4): self.add_widget(root.MyButton2(text = str(i), pos=self.pos))    
            #for i in range(1,3): self.add_widget(MyButton(text = str(i), pos=self.pos)) #<-- results in NameError: name 'MyButton' is not defined   

        MyButton: #<-- however this works fine
            text: '1'
''')

class MyButton(Button):

    def __init__(self, **kwargs):
        super(Button, self).__init__(**kwargs)    
        self.colours=cycle([(1,0,0,1),(0,1,0,1),(0,0,1,1)])
        
    def on_press(self):
        self.background_color=next(self.colours)

        
class MainWidget(BoxLayout):

    class MyButton2(MyButton):
        pass

class MyApp(App):
    def build(self):
        return MainWidget()
      
if __name__ == '__main__':
    MyApp().run()

Solution

  • You can fix that problem by using kivy.factory.Factory. Add to the beginning of your kv string:

    #:import Factory kivy.factory.Factory
    

    And then, use it as:

    for i in range(1,3): self.add_widget(Factory.MyButton(text = str(i), pos=self.pos))