How to import kv file from different directory

1,207 views
Skip to first unread message

GJG

unread,
Jan 28, 2021, 12:34:34 AM1/28/21
to kivy-...@googlegroups.com
This question is so basic I was afraid to ask it. I've read through the docs but I can't get imports to work correctly or at all for that matter. I've got a directory structure like so:
src/
├── __init__.py
├── main.kv
├── main.py
└── ui
    ├── __init__.py
    └── other_widgets.kv
Where I want to import widgets defined in ui/other_widgets.kv into main.kv. I keep getting a "kivy.factory.FactoryException: Unknown class <OtherWidget>" error. Below is my code:

main.py
from kivy.app import App
from kivy.lang import Builder


class MainApp(App):
def build(self):
Builder.load_file("ui/other_widgets.kv")
return Builder.load_file("main.kv")


if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 2.0.0
#:include ui/other_widgets.kv
FloatLayout:
canvas:
Color:
rgb: 0, 1, 0
Rectangle:
pos: self.pos
size: self.size

OtherWidget:
size_hint: 0.5, 0.5
other_widgets.kv
#:kivy 2.0.0
<OtherWidget>:
canvas:
Color:
rgb: 0, 0, 1
Rectangle:
pos: self.pos
size: self.size

Label:
text: "Other Widget"
What am I doing wrong?

Elliot Garbus

unread,
Jan 28, 2021, 10:41:54 AM1/28/21
to kivy-...@googlegroups.com

There are a few things going on here.

In other_widgets.kv, other_widgets is not inheriting from a widget base class so it is not defined.  Change to:

 

#:kivy 2.0.0
<OtherWidget@BoxLayout>:
   
canvas:
       
Color:
           
rgb: 0, 0, 1
       
Rectangle:
           
pos: self.pos
            size
: self.size

   
Label:
       
text: "Other Widget"

 

The you can decide either you include it in another file or you do a builder.load_file()

If you do builder.load_file, it must be done prior to build:

 

from kivy.app import App
from kivy.lang import
Builder

Builder.load_file(
'ui/other_widgets.kv')  #loading file prior to build

class MainApp(App):
   
def build(self):
       
return Builder.load_file("main.kv")


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

 

and remove the include in main.kv:

 

#:kivy 2.0.0

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CA%2Bqqht4BgdYbvwU9uWmznQWVL4nXdAwVf-Bf%3DUYF7i8QRine9A%40mail.gmail.com.

 

morsatici

unread,
Jan 28, 2021, 12:25:40 PM1/28/21
to Kivy users support
Thanks Elliot, this answers the question I originally asked but the same problem arises when I add properties in python:

other_widgets.py
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import StringProperty

Builder.load_file("other_widgets.kv")


class OtherWidget(BoxLayout):
other_property = StringProperty("foobar")
other_widgets.kv
#:kivy 2.0.0
<OtherWidget>: # I'm assuming kv lang knows OtherWidget is a BoxLayout from other_widgets.py?

canvas:
Color:
rgb: 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
main.py
from kivy.app import App
from kivy.lang import Builder

Builder.load_file("ui/other_widgets.kv")



class MainApp(App):
def build(self):
return Builder.load_file("main.kv")


if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 2.0.0
FloatLayout:
canvas:
Color:
            rgb: .9, .9, .9
        Rectangle:
pos: self.pos
size: self.size

OtherWidget:
        id: other_widget

Label:
text: other_widget.some_property
I sure it's something simple again, but I can't figure it out.

Elliot Garbus

unread,
Jan 28, 2021, 1:25:41 PM1/28/21
to kivy-...@googlegroups.com

In this case you would import the otherwidgets.py file into main. 

from kivy.app import App
from kivy.lang import Builder
import ui.other_widgets

# Builder.load_file('ui/other_widgets.kv')

class MainApp(App):
   
def build(self):
       
return Builder.load_file("main.kv")


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

 

In the the other_widgets.py file, the ‘trick’ is the need to specify the ui directory in the load_file call.  This code is being executed in the location it is being imported (main.py)

 

 

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

Builder.load_file(
"ui/other_widgets.kv")



class OtherWidget(BoxLayout):
    other_property = StringProperty(
"foobar")
 
 
In these cases I often like to combine the python and kv code into one file.  This removes the path dependency of the load_file call.
 
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import
StringProperty

Builder.load_string(
"""

<OtherWidget@BoxLayout>:
    canvas:
        Color:
            rgb: 0, 0, 1
        Rectangle:
            pos: self.pos
            size: self.size

    Label:
        text: "Other Widget"
""")


Reply all
Reply to author
Forward
0 new messages