I am receiving the Error : "KivyMD: App object must be initialized before loading " when I am trying to add a kivymd button (MDRaisedButton).
I tried debugging, the issue is when I add the BoxLayout under the DateScreen, I just don't find any information on how to fix it.
How should one initialized app object before loading ?
import kivy
kivy.require("1.11.1")
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen
from kivymd.theming import ThemeManager
class WelcomeScreen(Screen): # Defines WelcomeScreen instance as a screen widget.
pass
class DateScreen(Screen): # Defines DateScreen instance as a screen widget.
pass
class ResultScreen(Screen): # Defines ResultScreen instance as a screen widget.
pass
root_widget = Builder.load_string("""
ScreenManager:
WelcomeScreen:
DateScreen:
ResultScreen:
<WelcomeScreen>:
_welcome_screen_text_: welcome_screen
name: 'my_welcome_screen'
Label:
id: welcome_screen
Image:
source: 'Cheers.jpg'
size: 200, 200
center: self.parent.center
<DateScreen>:
_date_screen_text_: date_screen
name: 'my_date_screen'
Label:
id: date_screen
text: "This is the date selection screen"
BoxLayout:
size_hint: 0.1, 0.5
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDRaisedButton:
text: 'MDButton1'
<ResultScreen>:
_result_screen_text_: result_screen
name: 'my_result_screen'
Label:
id: result_screen
text: "This is where the result will be displayed"
""")
class MainApp(App):
theme_cls = ThemeManager()
def build(self):
self.theme_cls.theme_style = "Dark"
Clock.schedule_once(self.screen_switch_one, 36) # clock callback for the first screen
Clock.schedule_once(self.screen_switch_two, 4) # clock callback for the second screen
return root_widget
def screen_switch_one(a, b):
root_widget.current = 'my_welcome_screen'
def screen_switch_two(a, b):
root_widget.current = 'my_date_screen'
if __name__ == '__main__':
MainApp().run()
Please help!
I believe you need to call Builder after the App is initialized (as mentioned in your error). To do that you can save your kv in a string, then call Builder inside the build() method. Like this:
import kivy
from kivymd.app import MDApp
kivy.require("1.11.1")
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen
class WelcomeScreen(Screen): # Defines WelcomeScreen instance as a screen widget.
pass
class DateScreen(Screen): # Defines DateScreen instance as a screen widget.
pass
class ResultScreen(Screen): # Defines ResultScreen instance as a screen widget.
pass
kv = """
ScreenManager:
WelcomeScreen:
DateScreen:
ResultScreen:
<WelcomeScreen>:
_welcome_screen_text_: welcome_screen
name: 'my_welcome_screen'
Label:
id: welcome_screen
Image:
source: 'Cheers.jpg'
size: 200, 200
center: self.parent.center
<DateScreen>:
_date_screen_text_: date_screen
name: 'my_date_screen'
Label:
id: date_screen
text: "This is the date selection screen"
BoxLayout:
size_hint: 0.1, 0.5
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDRaisedButton:
text: 'MDButton1'
<ResultScreen>:
_result_screen_text_: result_screen
name: 'my_result_screen'
Label:
id: result_screen
text: "This is where the result will be displayed"
"""
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.root_widget = Builder.load_string(kv)
Clock.schedule_once(self.screen_switch_one, 36) # clock callback for the first screen
Clock.schedule_once(self.screen_switch_two, 4) # clock callback for the second screen
return self.root_widget
def screen_switch_one(self, dt):
self.root_widget.current = 'my_welcome_screen'
def screen_switch_two(self, dt):
self.root_widget.current = 'my_date_screen'
if __name__ == '__main__':
MainApp().run()
Related
I´m new using kivymd and trying to create a simple app, just for fun. I´m trying to create a register screen, but when I try to send the info to the console it returns me an error (kivy.properties.ObservableDict.getattr
AttributeError: 'super' object has no attribute 'getattr') and I actually don´t understand what it means.
.PY
'''
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.button import MDRoundFlatButton
from screen_helper import screen_helper
from kivy.core.window import Window
Window.size = (300, 500)
class MenuScreen(Screen):
pass
class LoginScreen(Screen):
pass
class RegistrarScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(LoginScreen(name='login'))
sm.add_widget(RegistrarScreen(name='registrar'))
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = 'Gray'
screen = Builder.load_string(screen_helper)
return screen
def show_data(self):
print(self.root.ids.user.text)
MainApp().run()
'''
.KV
'''
screen_helper = """
ScreenManager:
RegistrarScreen:
<RegistrarScreen>:
name: "register"
MDTextField:
id: user
hint_text: 'Enter your user'
pos_hint: {'center_x':0.5,'center_y': 0.8}
size_hint_x: None
width: 250
MDRoundFlatButton:
id: register_btn
text: "Registrarse"
text_color: 0, 0, 0, 1
line_color: 0, 0, 0, 1
pos_hint: {'center_x':0.5,'center_y': 0.1}
width: 500
on_press: app.show_data()
"""
'''
The problem is that your show_data() method is trying to access self.root.ids.user, but that id is not in the self.root widget (which is the ScreenManager). Try changing that method to:
def show_data(self):
print(self.root.get_screen('register').ids.user.text)
I am trying to run this type of code on android but when i tap mobile back button, inspite of coming to the previous screen app is closed,
i used this piece of code to stop the App for being closed:
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
Window.bind(on_keyboard=self.BackButton)
def BackButton(self, window, key, *args):
if key==27:
return True
But how to return to the previous screen. and how to use ActionPrevious Button to come at previous screen?
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MyAppGUI>:
orientation:'vertical'
id: box
ActionBar:
ActionView:
ActionPrevious:
title: 'How to go back using this button???'
with_previous: True
ScreenManager:
id: screenmanger
Screen:
name: 's1'
Button:
text: 'goto screen 2'
on_release: screenmanger.current='s2'
Screen:
name: 's2'
Button:
text: 'goto screen 3'
on_release: screenmanger.current='s3'
Screen:
name: 's3'
Button:
text: 'goto main screen'
on_release: screenmanger.current='s1'
""")
class MyAppGUI(BoxLayout):
pass
class MyApp(App):
def build(self):
return MyAppGUI()
if __name__=='__main__':
MyApp().run()
To return to the previous window using ActionPrevious button you just need to bind its on_release event to a function that uses current property to set the previous screen using the name returned by ScreenManager.previous () method or use a list that serves as a history of the windows visited. To use the Back key on Android, your code is correct in principle, at least on my device it works without problems:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<MyAppGUI>:
sm: screenmanger
orientation:'vertical'
id: box
ActionBar:
ActionView:
ActionPrevious:
title: 'How to go back using this button???'
with_previous: True
on_release: root.set_previous_screen()
ScreenManager:
id: screenmanger
Screen:
name: 's1'
Button:
text: 'goto screen 2'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s2'
Screen:
name: 's2'
Button:
text: 'goto screen 3'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s3'
Screen:
name: 's3'
Button:
text: 'goto main screen'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s1'
""")
class MyAppGUI(BoxLayout):
sm = ObjectProperty()
def __init__(self, **kwargs):
super(MyAppGUI, self).__init__(**kwargs)
Window.bind(on_keyboard=self._key_handler)
def _key_handler(self, instance, key, *args):
if key is 27:
self.set_previous_screen()
return True
def set_previous_screen(self):
if self.sm.current != 's1':
self.sm.transition.direction = 'left'
self.sm.current = self.sm.previous()
class MyApp(App):
def build(self):
return MyAppGUI()
if __name__ == '__main__':
MyApp().run()
I'm a beginner in kivy and python. I've been trying to create a scrollview in a page that displays selected video on the screen. But after a while when i selected 5-6 videos to display even though i delete the video widget it starts to lag. And i'm open to any suggestions to better way to handle this kind of application.
from kivy.config import Config
Config.set('graphics', 'width', '1920')
Config.set('graphics', 'height', '1080')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.properties import StringProperty
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.uix.button import Button
import os
from kivy.uix.video import Video
from kivy.uix.videoplayer import VideoPlayer
from kivy.clock import mainthread
from functools import partial
from kivy.core.window import Window
Window.clearcolor = (0, 0, 0, 0)
isThereVideo=False
picture_path="/home/linux/kivyFiles/kivyLogin/assets"
video_path="/home/linux/kivyFiles/kivyLogin/videoAssets/"
class Image(Image):
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class Selfie(Screen):
pass
class RootWidget(Widget):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
Clock.schedule_once(self.createMultipleButton)
#mainthread
def createMultipleButton(self, dt):
self.root = Widget()
size_y=150;
size_x=150;
for i in range(1):
folderList = os.listdir(picture_path)
if len(folderList)==0:
time.sleep(1)
break
fileList = os.listdir(picture_path)
print fileList
for file in fileList:
x = (picture_path+"/"+file)
button = Button(id=str(file),text="" + str(file),size_hint=(None, None),height=size_y,width=size_x, pos_hint={'x': 0, 'y': 1},background_normal=x)
button.bind(on_release=partial(self.VideoContainer, file))
print file
self.scrollview.content_layout.add_widget(button)
print button.id
print("Parent of ScreenTwo: {}".format(self.parent))
#print(button.pos)
def VideoContainer(self,name,btn):
global isThereVideo
if isThereVideo==True:
#self.videocontainer.video_layout.unload()
self.videocontainer.clear_widgets()
mylist=name.split('.')
emailButton = Button(id='email')
video = Video(source="/home/linux/kivyFiles/kivyLogin/videoAssets/"+mylist[0]+".mp4", state='play',options={'eos': 'loop'})
video.size=(self.parent.width,self.parent.height)
video_pos=(self.parent.x,self.parent.y)
#video.pos_hint={'x': self.parent.width /2, 'y': self.parent.height/2}
video.play=True
#video.pos=(self.parent.width /2 , self.parent.height/2)
#self.videocontainer.video_layout.add_widget(emailButton)
self.videocontainer.add_widget(emailButton)
emailButton.add_widget(video)
isThereVideo=True
print("Parent of ScreenTwo: {}".format(self.parent))
return 0
class ScreenManagement(ScreenManager):
pass
class VideoContain(Widget):
pass
class ScrollableContainer(ScrollView):
pass
presentation = Builder.load_file("login.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == '__main__':
Window.fullscreen = True
app=MainApp()
app.run()
And my Kv file
ScreenManagement:
MainScreen:
Selfie:
<MainScreen>:
name: 'main'
Button:
on_release: app.root.current = 'selfie'
text: 'Another Screen'
font_size: 50
<Selfie>:
name: 'selfie'
Button:
on_release: app.root.current = 'login'
text: 'Selfie Screen'
font_size: 10
pos_hint: {"right": 1, 'top':1}
size_hint: (0.1, 0.1)
RootWidget:
<RootWidget>
size_hint: (0.1, None)
scrollview: scrollview
videocontainer:videocontainer
size:(self.parent.width, self.parent.height)
VideoContain:
id:videocontainer
##size:(self.parent.width, self.parent.height)
size:(root.width, root.height)
ScrollableContainer:
id: scrollview
size: root.size
pos: root.pos
<VideoContain>
video_layout:video_layout
FloatLayout:
cols:1
id: video_layout
<ScrollableContainer>:
scroll_timeout: 75
scroll_distance: 10
app: app
content_layout: content_layout
GridLayout:
id: content_layout
cols: 1
size_hint: (0.1, None)
pos: root.pos
height: self.minimum_height
padding: 25
spacing: 25
I posted all my code since i don't know which part may causing the problem i'm facing.
Solved it.
def VideoContainer(self,name,btn):
global isThereVideo
if isThereVideo:
# self.videocontainer.video_layout.unload()
self.videocontainer.clear_widgets()
In this part i'm clearing the widgets but i also need to unload the video somehow.
self.video.unload() solved my problem
I need to dismiss the pop up after finishing a function in another class, or at least after specific time like (3 second)
the pop up displaying loading gif image
to notify the user to wait for operating the functions
loading image
*******python******
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class ScreenManagement(ScreenManager):
pass
class progress(Popup):
pass
class Func_(Screen):
# function
pass
presentation = Builder.load_file("Try_.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
********KV File*********
#:import Factory kivy.factory.Factory
<Popup>:
separator_color: 1, 1, 1, 1
background: "White.png"
Button:
id: btn
disabled: True
background_disabled_normal: "White.png"
text: "Hello"
Image:
source: "Loading.gif"
size: root.size
ScreenManagement:
PopupBox:
<PopupBox>:
BoxLayout:
Button:
text: "Click"
on_release:
Factory.Popup().open()
You have to add a function to dismiss the Popup message and use Clock.schedule_once to call that function. Please refer to the example below for details.
main.py
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
class ScreenManagement(ScreenManager):
pass
class Progress(Popup):
def __init__(self, **kwargs):
super(Progress, self).__init__(**kwargs)
# call dismiss_popup in 2 seconds
Clock.schedule_once(self.dismiss_popup, 2)
def dismiss_popup(self, dt):
self.dismiss()
class Func(Screen):
# function
pass
class MainApp(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
MainApp().run()
main.kv
#:import Factory kivy.factory.Factory
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<Progress>:
separator_color: 1, 1, 1, 1
background: "White.png"
Button:
id: btn
disabled: True
background_disabled_normal: "White.png"
text: "Hello"
Image:
source: "Loading.gif"
size: root.size
<ScreenManagement>:
transition: FadeTransition()
Func:
<Func>:
BoxLayout:
Button:
text: "Click"
on_release:
Factory.Progress().open()
Output
For the sake of brevity I'll explain my problem before posing the code. Here it goes:
I have a Screen class in Kivy that holds two widgets, a GridLayout and an Image. The latter is fine, but the buttons are extremely oversized:
And here's my main.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.factory import Factory
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivy.config import Config
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
import configparser
Builder.load_file('kv\MainMain.kv')
#read configurations
config = configparser.RawConfigParser()
config.read('config.ini')
#read config values
width = config.getint('Default', 'MAX_WINDOW_WIDTH')
height = config.getint('Default', 'MAX_WINDOW_HEIGHT')
border = config.getint('Default', 'BORDERLESS')
#apply config values
Config.set('graphics','width', width)
Config.set('graphics', 'height', height)
Config.set('graphics', 'borderless', border)
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
#create screen manager
class ScreenManager(ScreenManager):
pass
#create background widget
class BackGround(Image):
pass
#image buttons
class MainButtons(GridLayout):
pass
#create main screen:
class MainScreen(Screen):
pass
#create main app
class MainMainApp(App):
def build(self):
return MainScreen()
#register class
Factory.register(MainScreen, cls=MainScreen)
#run
if __name__ == '__main__':
MainMainApp().run()
And here's my kv file:
<ScreenManager>:
id: screen_manager
MainScreen:
id: main_screen
name: 'MainScreen'
manager: screen_manager
ReadScreen:
id: read_screen
name: 'ReadScreen'
manager: screen_manager
<MainScreen>:
BackGround:
id: back_ground
source: 'images\\app_background.jpg'
size: root.width, root.height
MainButtons:
cols: 1
pos: root.width / 2 - 100, root.height / 4
size: 20, 10
Button:
id: button_read
text: "Read"
on_press: root.callback_read()
Button:
id: button_add
text: "Add"
Button:
id: button_manage
text: "Manage"
I'm really swamped on this one. Thanks for your help.
You can use size_hint for this.
Here is an example
The pyhton file:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen,ScreenManager
Builder.load_file("my.kv")
class MainButtons(GridLayout):
pass
class MainScreen(Screen):
pass
class MainMainApp(App):
def build(self):
self.sm = ScreenManager()
self.sm.add_widget(MainScreen(name="main"))
return self.sm
if __name__ == '__main__':
MainMainApp().run()
and kivy file:
<MainScreen>:
MainButtons:
cols: 1
rows: 4
Label:
font_size: "40sp"
text: "Something"
Button:
size_hint: (1,0.1)
text: "Read"
Button:
size_hint: (1,0.1)
text: "Add"
Button:
size_hint: (1,0.1)
text: "Manage"
And output will be:
And if you want the buttons to be smaller in width, you add ´size_hint_x: None´ to your kv file, like this.
<MainScreen>:
MainButtons:
cols: 1
rows: 4
Label:
font_size: "40sp"
text: "Something"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Read"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Add"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Manage"
Output will now be: