How to fix when python recognizes only one .kv file - python

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)

Related

python, kivymd, builder, loadfile

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()

Switching between menus in kivy

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()

How to correctly remove a widget in Kivy if not added dynamically

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(
"""
&ltMenuScreen>:
BoxLayout:
id: box_layout
Button:
id: setBtn
text: 'Goto settings'
on_press: root.manager.current = 'settings'
Button:
text: 'Quit'
on_press: root.remove_settings()
&ltSettingsScreen>:
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')
# ...

How to write popup in kv file when one press button

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.factory import Factory
class My3App(App):
def build(self):
return Hello()
class Hello(Widget):
def btn(self):
pass
if __name__ == "__main__":
My3App().run()
kv File
<Hello>:
Button:
text : "button1"
on_press : root.btn()
How do I create a Popup when I click on button1? I want a large popup which contains so many buttons and labels. How do I write that popup in kv language?
Thanks in advance
Question 1
How do I create a Popup when I click on button1?
Solution
In this solution, it illustrates the use of dynamic class, and it involves changing both kv file and Python script.
kv file
Add import statement of Kivy Factory
Add a dynamic class, CustomPopup with inheritance of Popup widget
Add on_release event for button1 which use Kivy Factory to register and instantiate dynamic class, CustomPopup. Use Popup's open() method to display the Popup's window.
Snippets - kv
#:import Factory kivy.factory.Factory
...
<CustomPopup#Popup>:
...
<Hello>:
Button:
text : "button1"
on_release: Factory.CustomPopup().open()
Py file
Remove btn() method from class Hello()
Add pass to class Hello()
Snippets - Py
class Hello(Widget):
pass
Question 2
How do I write that popup in kv language?
Solution
There are two methods to implementing a class with Popup inheritance.
Method 1 - Using Dynamic Class
In this method, it involves changes to only kv file. We added a dynamic class rule.
Snippets - kv
#:import Factory kivy.factory.Factory
<CustomPopup#Popup>:
title: 'Test popup'
size_hint: (None, None)
size: (400, 400)
Label:
text: 'Hello world'
<Hello>:
Button:
text : "button1"
on_release: Factory.CustomPopup().open()
Method 2 - Using Normal Class
In this method, it involves changes to both kv file and Python script. We added a class rule in kv file, and implement a class in Python script.
Snippets - kv
<CustomPopup>:
title: 'Test popup'
size_hint: (None, None)
size: (400, 400)
Label:
text: 'Hello world'
<Hello>:
Button:
text : "button1"
on_press: root.btn()
Snippets - Py
from kivy.uix.popup import Popup
...
class CustomPopup(Popup):
pass
class Hello(Widget):
def btn(self):
popup = CustomPopup()
popup.open()
Question 3
I want a large popup which contains so many buttons and labels.
Solution
In this solution, we will be using dynamic class, and add buttons and labels into kv file. When creating a popup, you must at least set a Popup.title and Popup.content. The Popup.content can be any widget e.g. Screen, Layouts (BoxLayout, GridLayout, etc), Label, Button, etc. With a BoxLayout or GridLayout, you can add Label, and Button.
Snippets - kv
#:import Factory kivy.factory.Factory
<CustomPopup#Popup>:
title: 'My Custom Kivy Popup'
auto_dismiss: False
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.9
Label:
text: 'Hello'
Label:
text: 'Kivy'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Linux'
Label:
text: 'Python'
GridLayout:
rows: 1
row_force_default: True
row_default_height: '46dp'
col_force_default: True
col_default_width: '200dp'
Button:
text: 'Close this popup'
on_release: root.dismiss()
Button:
text: 'Cancel'
on_release: root.dismiss()
<Hello>:
Button:
text : "button1"
on_release: Factory.CustomPopup().open()
you should check this tutorial: https://kivy.org/doc/stable/api-kivy.uix.popup.html
MyPopup = Popup(title='Test popup', content=Label(text='Hello world'),
auto_dismiss=False
Button:
text: 'Open popup'
on_release: Factory.MyPopup().open()

.kv file doesn't seem to work

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.

Categories

Resources