How to solve".kv is loaded multiples times "error in Kivy? - python

I have a realy simple program in Kivy with 3 windows.But when I run it it says
The file C:\Users\ab79\Documents\GPX WEATHER\weather.kv is loaded multiples times, you might have unwanted behaviors.
I can run it but there is actually an unwanted behaviour, one of my three windows desappears !
When I run the code now it is skipping the "infoWindow" in the middle. I can observe it since I put FloatLayout instead of GridLayout, but the error message was already here before. I don't understand what's going wrong.
Here is the minimal code
python
today = datetime.datetime.now()
class ImportFileWindow(Screen):
pass
class InfoWindow(Screen):
pass
class ResultWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("weather.kv")
class WeatherApp(App):
def build(self):
return kv
if __name__=="__main__":
WeatherApp().run()
Kivy
WindowManager:
ImportFileWindow:
InfoWindow:
ResultWindow:
<Label>
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
font_size:40
color: 0,0,0,1
<Button>
font_size:40
color: 0,0,0,1
background_normal: ''
<ImportFileWindow>:
name: "import"
Button:
text: "Importer"
on_release:
app.root.current = "info"
root.manager.transition.direction="left"
<InfoWindow>:
name: "info"
day: day
FloatLayout:
cols:2
size:root.width,root.height/2
Label:
text:"Jour :"
TextInput:
id:day
multiline:False
Button:
text:"Valider"
on_release:
app.root.current="result"
root.manager.transition.direction="left"
Button:
text:"Retour"
on_release:
app.root.current="import"
root.manager.transition.direction="right"
<ResultWindow>:
name: "result"
Button:
text: "Retour"
on_release:
app.root.current="info"
root.manager.transition.direction="right"
```
The error is are since the begining but the real issues are here since I use a FloatLayout instead of GridLayout.
Any ideas ?
:)

The file weather.kv is loaded automatically, see documentation. But you are also loading it explicitly with:
kv = Builder.load_file("weather.kv")
I think you just need to delete the above line, and change your WeatherApp class to:
class WeatherApp(App):
pass

You have to assign full code of your 'kv' file in to a variable(ex:- kv = """kv code here"""). And create a new function to load it using Builder.load_string(kv). After that use 'kivy.clock' module to schedule that function once when the build method is started.

Related

Adding RelativeLayout to existing app in kivy file

So what I am trying to achieve is:
class FirstWindow(Screen):
layout=self.ids['second']
lab1=Label(text="one",size_hint_x=.35)
lab2=Label(text="two",size_hint_x=.35)
layout.add_widget(lab1)
layout.add_widget(lab2)
<FirstWindow>:
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Image:
source: "gui-background.jpg"
size_hint: None, None
size: root.size
allow_stretch: True
keep_ratio: False
RelativeLayout:
id: second
cols:2
size_hint:(0.5, 0.4)
pos_hint:{'x':0, 'y': 0.6}
I want to add both Labels to the RelativeLayout with id: second. The issue that code shows is:
How do I fix it?
I resolved my problem with adding this entire stuff into a simple function
class FirstWindow(Screen):
def abc(self):
layout=self.ids['second']
lab1=Label(text="one",size_hint_x=.35)
lab2=Label(text="two",size_hint_x=.35)
layout.add_widget(lab1)
layout.add_widget(lab2)
Then it's just calling it with a button.
Button:
text: "click"
on_press: root.abc()
I read that it's problematic because self is an argument only available at function call time.

How do I load an image into a kivy window using a button?

I am trying to use kivy with Python to develop a quick app with sliders where one has to use the sliders first to determine a setting and then click a 'Submit' which then loads the desired image into the app window.
I currently have examples in my .kv file to insert a button and an image indiviudally, but I'm not sure how to connect them:
BoxLayout:
orientation:'vertical'
size: root.width,root.height
font_size: 20
padding: 100
spacing: 10
Button:
text: 'press me'
on_press: print("ouch! More gently please")
on_release: print("ahhh")
on_state:
#print("my current state is {}".format(self.state))
size_hint: (0.3,0.3)
Image:
source: 'images\IMG_6980.jpg'
#allow_stretch: True
#keep_ratio: True
pos_hint: {'center_x':0.7}
I feel like I need to do something with the on_press statement but I'm not quite sure what. Any help is appreciated.
I have given you an example below of how to generate an image from a button using the on_press method as you have described. By using the factory module, you can generate templates created in your *.kv files. So to complete your program, you would create more of these templates, and then generate the appropriate image template in your on_press method using conditionals. You could alternatively try to create dynamic templates within Python, but I believe my example to be more simple.
test.py:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class TestBoxLayout(BoxLayout):
pass
class TestApp(App):
def build(self):
return TestBoxLayout()
if __name__ == '__main__':
TestApp().run()
test.kv:
#: import Factory kivy.factory.Factory
<TestImage#Image>:
source: 'test.jpg'
#allow_stretch: True
#keep_ratio: True
pos_hint: {'centre_X':0.7}
<TestBoxLayout>:
orientation:'vertical'
size: root.width,root.height
font_size: 20
padding: 100
spacing: 10
Button:
text: 'press me'
on_press: root.add_widget(Factory.TestImage())
on_release: print("ahhh")
on_state:
#print("my current state is {}".format(self.state))
size_hint: (0.3,0.3)
To extend this solution to your comment, I have given a further example below. I want to reiterate that my example is designed to be simple to understand and can certainly be done more efficiently, but hopefully this acts as a clear solution to your problem. Please mark this as the best answer if this fulfils your needs!
test.kv:
#: import Factory kivy.factory.Factory
<TestImage1#Image>:
source: 'test_1.jpg'
#allow_stretch: True
#keep_ratio: True
pos_hint: {'centre_X':0.7}
<TestImage2#Image>:
source: 'test_2.jpg'
#allow_stretch: True
#keep_ratio: True
pos_hint: {'centre_X':0.7}
<TestBoxLayout>:
orientation:'vertical'
size: root.width,root.height
font_size: 20
padding: 100
spacing: 10
Slider:
id: slider
min: 1
max: 2
step: 1
Button:
text: 'press me'
on_press:
if slider.value == 1: root.add_widget(Factory.TestImage1())
elif slider.value == 2: root.add_widget(Factory.TestImage2())
on_release: print("ahhh")
on_state:
#print("my current state is {}".format(self.state))
size_hint: (0.3,0.3)

Updating Kivy Label Using Threading

I am trying to make a Kivy label that shows a string that is just a list of names. My end goal is to make it so you can add or remove to the list of names and the label will indicate the names on the list. As of now I have a label and a function in my .py file that compiles the list of names into a string.
Each name in the string is separated by a "\n". My problem however, is that the label does not update and show the names even though the function returns the names. I researched this problem and heard about threading. However, I do not understand how to use it in my case and am asking for some guidance.
Below is my code:
kv CODE:
<SettingsWindow>:
name:"settings"
FloatLayout:
Widget:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "Images/logo_br.png"
Color:
rgba: 0,0,0,.5
Rectangle:
size: 200, 330
pos: self.width/10, self.height/4
Button:
text:"Back"
size_hint: 0.1, 0.1
pos_hint: {"x":0, "y":0}
background_color: 1,1,1,.6
on_release:
app.root.current = "main"
root.manager.transition.direction = 'right'
Label:
text: root.pretty_list_people
size: self.texture_size
pos_hint: {"x":0.35, "y":-0.46}
color: 1,1,1,1
Button:
text:"Show Bros"
size_hint: 0.3, 0.3
pos_hint: {"x":0.3, "y":0.1}
on_press: root.Pretty_Print_People(root.get_str_People())
py CODE:
class SettingsWindow(Screen):
pretty_list_people = ""
def get_str_Jobs(self):
return WindowManager.jobs
def get_str_People(self):
return WindowManager.people
def Pretty_Print_People(self, ppl_list):
for person in ppl_list:
self.pretty_list_people += person + "\n"
class HelpWindow(Screen):
pass
class WindowManager(ScreenManager):
jobs = ["Scrub", "Wash", "Clean"]
people = ["Anthony", "Tim", "John"]
job_assignments = {}
I tried to show only the necessary code.
This should work, uses kivy properties:
Change:
pretty_list_people = ""
To:
pretty_list_people = StringProperty ("")
And add the import:
from kivy.properties import StringProperty
At the start of your program
Hope this helps you to solve your problem

kivy pass value from one screen to another screen after popup conformation

I have two screens one have input and other shows the output.When the input is entered and go button is pressed a popup must appear and show 'do you want to transfer the value?'. If No is pressed goto the second screen and show the previous value. if yes is pressed goto the second screen and show the new value in the kivy screen. Need help.
py
from kivy.properties import StringProperty,ObjectProperty
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
class Screen1(Screen):
text = StringProperty('')
def changetext(self):
self.text = self.text11.text
def erroropen(self):
Error_Change().open()
class Error_Change(Popup):
def changetext(self):
Screen1().changetext()
class Screen2(Screen):
label_text = StringProperty('')
class screenApp(App):
pass
screenApp().run()
kv
ScreenManager:
id: screen_manager
Screen1:
id: screen_1
name: 'screen1'
Screen2:
name: 'screen2'
label_text: screen_1.text
<Screen1>:
text11:text11
BoxLayout:
orientation:'vertical'
TextInput:
id:text11
Button:
text: 'Screen 2'
on_press:
root.manager.current='screen2'
Button:
text: 'Set Value and go to screen 2'
on_press:
root.erroropen()
<Error_Change>:
id:pop3
title:'Alert!!!'
size_hint: .65,.4
auto_dismiss: False
BoxLayout
orientation: 'vertical'
spacing:0
padding:[0,0,0,10]
size:self.size
Label:
text:'Do you want to start cycling with this configuration?'
font_size:20
bold:True
BoxLayout:
orientation: 'horizontal'
font_size:15
padding:[30,10,30,10]
size_hint:1,.6
spacing:20
Button:
text:'Continue'
on_release:
root.changetext()
app.root.current='screen2'
pop3.dismiss()
bold:True
background_normal: ''
background_color: (.75, .2, .01,1)
Button:
text:'Cancel'
on_release: pop3.dismiss()
bold:True
background_normal: ''
background_color: (.1, .8, 0,1)
<Screen2>:
BoxLayout:
Label:
text: root.label_text
Button:
text: 'Screen 1'
on_press:
root.manager.current='screen1'
I don't know why, but it's a very common mistake that you do. It basically comes down to a misunderstanding of the difference between classes and instances in python, or at least which is which when it comes to kivy widgets.
in change_text, you create a new Screen1 instance, instead of using the existing one on your app. That will not have any effect, as this new instance is not added to your app (and shouldn't be), and will be destroyed as soon as python understands that it's not used for anything.
What you want, is to get a reference to your existing Screen1 instance, one way to get that is by first getting a reference to your App instance, and use the ids attribute of it's root attribute (which points to the base of your widget tree).
You can use App.get_running_app() to get the "app" object, (same as app in kv), and use app.root.ids.screen_1.change_text(), with the right parameter. Or you could just bypass this step, and directly call app.root.ids.screen_1.change_text() from kvlang.

Kivy - base application has strange alignment

I am trying to build a basic Kivy app. After adding the basic elements, and running the app, all of the elements are crammed into the bottom left corner. It shows up like this on android and Linux.
Main.py:
from kivy.app import App
from kivy.uix.widget import Widget
class SublimeLauncher(Widget):
pass
class SublimeLauncherApp(App):
def build(self):
return SublimeLauncher()
if __name__ == "__main__":
SublimeLauncherApp().run()
sublimelauncher.kv:
#:kivy 1.2.0
<SublimeLauncher>:
FloatLayout:
BoxLayout:
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
I first tried it with just the BoxLayout, but read somewhere the root widget is always as big as the app. How do I declare the size of the app? Or the layout? How would you go about doing something like a dialog box?
Maybe I am missing something very basic, but I can't seem to figure it out.
Edit: here is what I am seeing..
Your layout has a default size of 100x100 pixels. You can try to color it to see how much space does it take:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
kv = '''
<SublimeLauncher>:
BoxLayout:
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
class SublimeLauncher(Widget):
pass
class SublimeLauncherApp(App):
def build(self):
return SublimeLauncher()
if __name__ == "__main__":
SublimeLauncherApp().run()
Setting non-default size:
kv = '''
<SublimeLauncher>:
BoxLayout:
size: 250, 250
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
Taking full space:
kv = '''
<SublimeLauncher>:
BoxLayout:
size: root.size
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open. \\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
I recently wrote a post of a little trick I use when I am programming interfaces. The trick will let you see a border around all the widgets (layouts included) you add to the screen. This would be the result for your code:
It takes advantage of inheritance and the Kivy rules to overwrite the base class of all widgets. You just have to add:
<Widget>:
canvas.after:
Line:
rectangle: self.x+1,self.y+1,self.width-1,self.height-1
at the beginning of this file:
<SublimeLauncher>:
FloatLayout:
BoxLayout:
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
As your root widget is not a layout (you made SublimeLauncher inherit Widget), it doesn't set its children size/positions. So your FloatLayout have the defaults, since you don't override them manually either.
pos: 0, 0
size: 100, 100
And these defaults of course constraints the child, since FloatLayout by constraint their size based on their size_hint property.
You want to give them more space, as Nykakin pointed out.
Also, as your text is bigger than the Label (you didn't set halign and text_size either) its texture is centered on the center of the Label, and so some part of it is out of screen. You want to have a look at kivy/examples/widgets/textalign.py

Categories

Resources