I am just learning some styles and designs of kivymd, but for some reason when the code runs
kv = Builder.load_file(MainLayout.kv), it raises the Exception(
kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget.
).
I just can't get it to run and any further. It has been raising this Exception no matter what changes I make.
And Just for Reference, this is the Code for the Main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.list import MDList
from kivymd.theming import ThemableBehavior
from kivy.core.window import Window
class Login(Screen):
pass
class Settings(Screen):
pass
sm = ScreenManager()
sm.add_widget(Login(name='login'))
sm.add_widget(Settings(name='settings'))
sm.current = "login"
class DemoApp(MDApp):
class ContentNavigationDrawer(BoxLayout):
pass
class DrawerList(ThemableBehavior, MDList):
pass
def build(self):
self.theme_cls.primary_palette = "Teal"
Window.size = (412, 732)
#The Error Occurs when the KV file is loaded
kv = Builder.load_file("MainLayout.kv")
return kv
if __name__ == '__main__':
DemoApp().run()
This the Kivy File and in Login File I just have ( )
#: include Login.kv
#: include Settings.kv.
NavigationLayout:
id:nav_layout
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Kivy Demo App"
Widget:
ScreenManager:
id: screen_manager
Login:
id: login1
name: "login"
Settings:
id: settings1
name:"settings"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: 'vertical'
padding: "8dp"
spacing: "8dp"
MDLabel:
text: 'Username'
MDLabel:
text: 'Captions'
Okay, it was not too hard to fix this. I just Changed the name of the class/page from settings to just setting and it fixed the problem. Not really sure how it affected the code but would love to know about the bug if anyone might know.
I ran into the same problem. The class name "Settings" causes the error "ScreenManager accepts only Screen widget". I changed the class name to "Setting" and the screen widget's id and name both to "setting" and everything works fine. Frustrating.
Related
.py file
this is python code
When I start the program it gives me a blank, black screen. I used the python file for the functionality and the kv file for the properties of the objects. Py file:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file('design.kv')
class LoginScreen(Screen):
pass
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__=="__main__":
MainApp().run()
.kv file
this is kv script
<LoginScreen>:
GridLayout:
cols:1
GridLayout:
cols:1
Label:
text: "User Login"
TextInput:
hint_text: "Username"
TextInput:
hint_text: "Password"
Button:
text: "Login"
GridLayout:
cols:2
Button:
text: "Forgot password"
Button:
text: "Sign Up"
<RootWidget>:
name: "Login_screen"
You need to load the file at the end of the script, and then return it inside the build method:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class LoginScreen(Screen):
pass
class RootWidget(ScreenManager):
pass
kvfile = Builder.load_file('design.kv')
class MainApp(App):
def build(self):
return kvfile
if __name__=="__main__":
MainApp().run()
Prior to making it a multiple screen application there were no issues but now that I have made it one I get the error :
if self.light_novel_list.adapter.selection:
AttributeError: 'NoneType' object has no attribute 'adapter'
Whenever I press the delete button while selecting an item in my list object.
As I am getting a NoneType error I think that I am referring to the object in the kivy hierarchy incorrectly somehow but I am unsure how.
My relevant code is:
lightnovel.py:
import kivy
from urllib.request import Request, urlopen
from kivy.uix.screenmanager import ScreenManager, Screen
from bs4 import BeautifulSoup
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.listview import ListItemButton
from kivy.properties import StringProperty
class SavedListButton(ListItemButton):
pass
class LightNovel(Screen):
light_novel_text_input = ObjectProperty()
light_novel_list = ObjectProperty()
def delete(self):
if self.light_novel_list.adapter.selection:
selection = self.light_novel_list.adapter.selection[0].text
self.light_novel_list.adapter.data.remove(selection)
self.light_novel_list._trigger_reset_populate()
class Series(Screen):
pass
class LightNovelApp(App):
def build(self):
screen_manager = ScreenManager()
screen_manager.add_widget(LightNovel(name="screen_one"))
screen_manager.add_widget(Series(name="screen_two"))
return screen_manager
lnApp = LightNovelApp()
lnApp.run()
lightnovel.kv:
#: import main lightnovel
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
<LightNovel>:
BoxLayout:
light_novel_text_input: searchbar
light_novel_list: saved
orientation: "vertical"
id: main
BoxLayout:
id: secondbar
size_hint: 1, .1
Button:
id: delete
size_hint: .5, 1
text: "Delete"
on_press: root.delete()
Button:
id: goto
size_hint: .5, 1
text: "Go to"
on_press:
root.goto()
root.manager.transition.direction = 'left'
root.manager.transition.duration = 1
root.manager.current = 'screen_two'
ListView:
id: saved
adapter:
ListAdapter(data=["test"], cls=main.SavedListButton)
I have cut out unnecessary code so that it is easier to read but all of my self.-references in my other functions also fail which is part of why I think I am referencing them incorrectly.
Your error is that you define light_novel_text_input in the boxlayout.
<LightNovel>:
BoxLayout:
light_novel_text_input: searchbar
light_novel_list: saved
When you might want this, because the ObjectPropertys belongs to the LightNovel class:
<LightNovel>:
light_novel_text_input: searchbar
light_novel_list: saved
BoxLayout:
i have a simple test program:
main.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen
from kivy.clock import mainthread
class TestScreen(Screen):
#mainthread
def on_pre_enter(self): #Is loaded before kv buttons etc? how make it work
pass
#mainthread
def on_enter(self): #Load after kv buttons etc?
button = Button(text="Work?")
#how now add it to display?
#how control where display it? on end or begin is just about on_pre and on?
class TestApp(App):
pass
if __name__ == '__main__':
TestApp().run()
And test.kv file
#:import NoTransition kivy.uix.screenmanager.NoTransition
<TestScreen>:
name:'try'
GridLayout:
id:'test'
cols:2
Button:
text:'Test'
on_press:app.root.current='Main'
ScreenManager:
transition: NoTransition()
Screen:
name: 'Main'
GridLayout:
cols:1
Button:
text:'1'
Button:
text:'2'
Button:
text:'Test'
on_press:root.current='try'
TestScreen:
Is simple to control kv and python widgets(but i dont know how but is more easy to writes widgets etc in kv file, but still need create some in python for automatic content) or better just create all in python withou kv file? I wanna make somehting like this: App with left menu always displayed and on the right side another screen with dynamic content based on screen(clicked from menu) is maybe another simple solution for this. Anyone can explain me step by step? :)
AttributeError
The solution to AttributeError, please replace "id: 'test'" with "id: test" in test.kv file.
Dynamic Content
It is possible to display screen with dynamic content based on clicked from menu. But remember to remove the widgets that were added when exiting the screen (TestScreen/SettingsScreen). If you do not remove the widgets, you will get duplicates/multiples of each widget added each time you enter the screen (TestScreen/SettingsScreen). I recommend using on_pre_enter and on_leave methods. Please refer to the example below for details.
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
class MyScreenManager(ScreenManager):
pass
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
def on_pre_enter(self, *args):
self.ids.test.add_widget(Button(text="Work?"))
def on_leave(self, *args):
self.ids.test.remove_widget(self.ids.test.children[0])
class TestApp(App):
title = "Add & Remove Widgets Dynamically"
def build(self):
return MyScreenManager()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import NoTransition kivy.uix.screenmanager.NoTransition
<MyScreenManager>:
transition: NoTransition()
MenuScreen:
SettingsScreen:
<MenuScreen>:
name: 'menu'
GridLayout:
cols: 1
Button:
text: '1'
Button:
text: '2'
Button:
text: 'Test'
on_press: root.manager.current = 'settings'
<SettingsScreen>:
name:'settings'
GridLayout:
id: test
cols: 2
Button:
text: 'Test'
on_press: root.manager.current = 'menu'
Output
I have the same issue like described in this theme kv incorrect. When I use Builder and load the kv file I have normal working app. But when I try to use autoload kv file I have only black screen. Could someone explain me why? Thanks for any help.
My code. main.py
import kivy
kivy.require('1.9.1') # replace with your current kivy version !
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class Test(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
Test().run()
kv file. test.kv
#:kivy 1.9.1
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
on_release: app.root.current = "other"
text: "Next Screen"
font_size: 50
<AnotherScreen>:
name: "other"
Button:
on_release: app.root.current = "main"
text: "Prev Screen"
font_size: 50
In your kv file, you define ScreenManagement to be the root element with its associated screens. But in build, you return a newly created ScreenManagement object, which will not have any children defined.
Solution:
Define build as
def build(self):
pass
or change the definition of ScreenManagement in the kv file to
<ScreenManagement>:
transition: FadeTransition()
MainScreen:
AnotherScreen:
so this will apply to all new ScreenManagement objects.
you can also add:
from kivy.properties import ObjectProperty
then change:
class ScreenManagement(ScreenManager):
pass
to this:
class ScreenManagement(screenManager):
mainscreen = ObjectProperty(None)
anotherscreen = ObjectProperty(None)
then in your .kv file you want to change this:
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
to this:
<ScreenManagement>:
transition: FadeTransition()
mainscreen: mainscreen
anotherscreen: anotherscreen
then for your MainScreen add and id like so:
<MainScreen>:
id: mainscreen
and do the same for you AnotherScreen.
Check the version of your Python and the version of Pygame you're using. I got that problem and my issue came from the version of Pygame.
I'm trying to get the nickname from the intro screen and then build the chat screen using this nickname in a label. However, I can't get my function to work with ids properly.
.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
Screens:
transition: FadeTransition()
Intro
Chat
<Intro>:
id: intro
TextInput:
id: intro_text
...
Button:
...
on_press: root.intro_bt_press()
<Chat>:
name: "main"
Label:
id: lb_name
.py:
from kivy import require
require("1.9.1")
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager, FadeTransition
from kivy.lang import Builder
nick = ""
class Chat(Screen):
lb_name.text = "Chat with {}".format(nick)
class Intro(Screen):
global nick
def intro_bt_press(self):
nick = intro_text.text
App.get_running_app().root.current = "main"
class Screens(ScreenManager):
pass
Screens = Builder.load_file("chat.kv")
class Chat(App):
def build(self):
return Screens
if __name__ == "__main__":
Chat().run()
So when the button is pressed, I want to get the text from TextInput, switch to the main screen and format the label on that screen with the text. I can't assign the text to the variable "nick" because it says that it's not defined. And the same goes for lb_name, but I can't even get past the first error. What am I missing before the id to tell Python, where in the kv file to look?
The ids assigned in kv are available in the ids
property. if you want to access the widgets in your Python file, use something like self.ids['intro_text'].text in intro_bt_press.
However, the desired behaviour can be achieved just using the kv language:
This is chat.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
<Screens#ScreenManager>:
Screens:
transition: FadeTransition()
Intro
Chat
<Intro#Screen>:
BoxLayout:
TextInput:
id: intro_text
Button:
on_press:
root.manager.get_screen('main').ids.lb_name.text = root.ids.intro_text.text
root.manager.current = "main"
<Chat#Screen>:
name: "main"
Label:
id: lb_name
And this is chat.py:
from kivy.app import App
class ChatApp(App):
pass
if __name__ == "__main__":
ChatApp().run()