I have a seemingly pretty easy question. I am making a app with kivymd and the first .kv file is sort of long. I have three .kv files that I would like to navigate in between. Currently i'm wondering how to use Builder.load_file, or something else to read from window to window, thanks for your help.
Not sure if there is a better way to do this or not. I myself couldn't find anything but ended up doing the following.
Create your main .kv file that is a screen manager. Make sure you include your other .kv files with '#:include 'filename.kv'
#:include screen1.kv
#:include screen2.kv
ScreenManager:
Screen1:
Screen2:
Format your other .kv files however you'd like. Just make sure to include a name for referencing in your screen manager. You must also name the screens the same as you did in your main.kv file.
<Screen1>
name: 'screen1'
orientation: 'vertical'
MDLabel:
text: 'Screen1'
halign: 'center'
MDFlatButton:
text: 'Go to screen 2'
pos_hint: {'center_x': 0.5}
on_release: root.manager.current = 'screen2'
This is .kv file #2
<Screen2>
name: 'screen2'
orientation: 'vertical'
MDLabel:
text: 'Screen2'
halign: 'center'
MDFlatButton:
text: 'Go to screen 1'
pos_hint: {'center_x': 0.5}
on_release: root.manager.current = 'screen1'
Your main.py file will have to include the libraries, define the classes, add the screens to your screen manager, and then you can build your main.kv file in your MDApp.
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
class Screen1(Screen):
pass
class Screen2(Screen):
pass
sm = ScreenManager()
sm.add_widget(Screen1(name= 'screen1'))
sm.add_widget(Screen2(name= 'screen2'))
class MainApp(MDApp):
def build(self):
sm = Builder.load_file("Main.kv")
return sm
MainApp().run()
Related
I am making a simple GUI with kivy. made twi screens but facing a problem.
PROBLEM: Previous is still visible behind the current screen.
check screenshots:
First Screen..
enter image description here
second screen where first screen is still visible..
enter image description here
main.py code
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):
def sign_up(self):
self.manager.current = "signup_screen"
class SignUpScreen(LoginScreen):
pass
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MainApp().run()
Here, design.kv
<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"
on_press:root.sign_up()
<SignUpScreen>:
GridLayout:
cols:1
Label:
text:"Welcome to Another Dimension, Bitch!"
TextInput:
hint_text:"New Username"
TextInput:
hint_text:"New Password"
GridLayout:
cols:2
Button:
text:"Submit"
Button:
text:"Cancel"
<RootWidget>:
LoginScreen:
name:"login_screen"
SignUpScreen:
name:"signup_screen"
The problem here is that you inherited your SignUpScreen from your LoginScreen, which is why the widgets of the login screen is still in the signup one. The simple solution here is to instead inherit your SignUpScreen from the Screen class:
class SignUpScreen(Screen):
pass
I use kivy to make a basic menu.
This results in a pretty simple menu. So far so good.
The problem
When I click the settings button, I want the app to clear the screen and execute SettingsMenu which is supposed to create a button, which should allow me to go back to the main menu. However, pressing the settings button only clears the screen, and doesn't add any new buttons.
How can I go back and forth between these menus?
Also, what is the right terminology to use here - How do I draw new widgets on my root widget?
The python file:
import kivy
from kivy.app import App
from kivy.uix.stacklayout import StackLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.widget import Widget
class StartMenu(AnchorLayout):
def go_to_settings(self):
self.clear_widgets()
return SettingsMenu()
class SettingsMenu(AnchorLayout):
def go_to_main_menu(self):
self.clear_widgets()
return StartMenu()
class SpaceGameApp(App):
def build(self):
return StartMenu()
if __name__ == '__main__':
SpaceGameApp().run()
And the .kv file:
#:kivy 1.11.1
<StartMenu>:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
size_hint: (0.3,0.5)
StackLayout:
spacing:10
Button:
size_hint: (1,0.2)
text: "start"
Button:
size_hint: (1,0.2)
text: "settings"
on_release: root.go_to_settings()
<SettingsMenu>:
AnchorLayout:
anchor_x:'center'
anchor_y:'center'
size_hint: (0.3, 0.5)
StackLayout:
spacing:10
Button:
size_hint: (1,0.2)
text: "back"
on_release: root.go_to_main_menu()
I see there are a lot of answers for a case similar to mine: if I add a widget in code with the ".add_widget()" function, I can later remove this widget with the ".remove_widget()" function.
My case is a little bit different: I'm trying to remove a button in a Screen that is added in the configuration file (this has not a separated kv file because I'm still doing some research to well understand the mechanics under Kivy).
I'm trying to remove the button with id "setBtn" inside the "MenuScreen" screen.
I tried several ways to do this, but no one worked for me.
I'm not even sure that there is a solution to remove a widget that has not been dynamically added to a parent widget...
I leave you my code, if anyone could help me I'd be very grateful.
Thank you.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
# Create both screens. Please note the root.manager.current: this is how
# you can control the ScreenManager from kv. Each screen has by default a
# property manager that gives you the instance of the ScreenManager used.
Builder.load_string("""
<MenuScreen>:
BoxLayout:
Button:
id: 'setBtn'
text: 'Goto settings'
on_press: root.manager.current = 'settings'
Button:
text: 'Quit'
on_press: root.remove_settings()
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
""")
# Declare both screens
class MenuScreen(Screen):
def remove_settings(self):
sm.remove_widget(settings)
self.remove_widget(self.ids.setBtn)
print 'Screen "settings" removed succesfully'
class SettingsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
menu = MenuScreen(name='menu')
settings=SettingsScreen(name='settings')
sm.add_widget(menu)
sm.add_widget(settings)
class TestApp(App):
def build(self):
return sm
def exit(self):
self.exit()
if __name__ == '__main__':
TestApp().run()
You have 2 errors:
The ids are not strings.
If you want to remove a widget you must use it through your parent, in your case if you want to remove the "setBtn" then you must use the BoxLayout.
Considering the above, the solution is:
# ...
Builder.load_string(
"""
<MenuScreen>:
BoxLayout:
id: box_layout
Button:
id: setBtn
text: 'Goto settings'
on_press: root.manager.current = 'settings'
Button:
text: 'Quit'
on_press: root.remove_settings()
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
"""
)
# Declare both screens
class MenuScreen(Screen):
def remove_settings(self):
self.ids.box_layout.remove_widget(self.ids.setBtn)
print('Screen "settings" removed succesfully')
# ...
I just started learning Kivy today. The book i am referring to uses kv files. The problem is when i create more than one .kv file, and when i import the other one, it doesn't work. Please any detailed help will be appreciated as i am a complete beginner. Thanks
I already searched alot and tried from places, but nothing seems to work.
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.lang import Builder
class AddLocationForm(BoxLayout):
pass
class WeatherApp(App):
pass
if __name__ == '__main__':
WeatherApp().run()
AddLocationForm.kv
AddLocationForm:
<AddLocationForm#BoxLayout>:
orientation: "vertical"
BoxLayout:
TextInput:
Button:
text: "Search"
Button:
text: "Current Location"
weather.kv
BoxLayout:
Label:
text: "Hello"
Label:
text: "Awesome"
Label:
text: "World"
I want it to print the strings, and show the button as well.
You can also use Builder to load kv files or strings.
from kivy.lang import Builder
Builder.load_file("kvfile1.kv")
Builder.load_file("kvfile2.kv")
Use Kv Language Directives, include <file>
Snippets - weather.kv
#:include AddLocationForm.kv
AddLocationForm:
BoxLayout:
Label:
text: "Hello"
Label:
text: "Awesome"
Label:
text: "World"
Snippets - AddLocationForm.kv
<AddLocationForm#BoxLayout>:
orientation: "vertical"
BoxLayout:
TextInput:
Button:
text: "Search"
Button:
text: "Current Location"
Output
Kv language ยป Lang Directives
include <file>
Syntax:
#:include [force] <file>
Includes an external kivy file. This allows you to split complex
widgets into their own files. If the include is forced, the file will
first be unloaded and then reloaded again. For example:
# Test.kv
#:include mycomponent.kv
#:include force mybutton.kv
<Rule>:
state: 'normal'
MyButton:
MyComponent:
# mycomponent.kv
#:include mybutton.kv
<MyComponent>:
MyButton:
# mybutton.kv
<MyButton>:
canvas:
Color:
rgb: (1.0, 0.0, 0.0)
Rectangle:
pos: self.pos
size: (self.size[0]/4, self.size[1]/4)
So I'm just working with some example Kivy file code, and I came across this code which allows the user to switch between screens:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MenuScreen>:
BoxLayout:
Button:
text: 'Build Scenario'
on_press: root.manager.current = 'settings'
Button:
text: 'Run Existing Scenerio'
<SettingsScreen>:
BoxLayout:
Button:
text: 'Run Existing Scenerio'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
""")
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
I wondered to myself if it would be possible to put the code given in the Builder.load_string() method into a separate .kv file. So I did just that. I commented the Builder part out (I admit I don't know what its role is) and copied the string into a .kv file which looks like this:
# the file name is test.kv
#:kivy 1.0.9
<MenuScreen>:
BoxLayout:
Button:
text: 'Build Scenario'
on_press: root.manager.current = 'settings'
Button:
text: 'Run Existing Scenerio'
<SettingsScreen>:
BoxLayout:
Button:
text: 'Run Existing Scenerio'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Unfortunately when I run the code now I just get a black screen. Can anyone tell me what's wrong? Thanks!
The code creates the screenmanager (sm) in the main body of the python file. When the kv is loaded from a file this only happens later, so none of the kv rules are applied to sm. It was okay before because the load_string happens before it is instantiated.
For this reason, instantiating widgets this way is bad practice, and the sm = ScreenManager(... etc should be moved to the build method. This is run after the kv file is loaded, so everything should work.