I need some help with kivy,i am pretty new to kivy and I made a class to to draw a rectangle as a background.
I am pretty sure I did everything correctly but there is an error,so here is my code
The .py file
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
class Background(Widget):
pass
class MY_browser(App):
def build(self):
return Background
MY_browser().run()
The .kv file
Floatlayout:
Background:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
I have tried a lot of things but no difference so if anyone can help I would really appreciate it
A couple problems:
In your build() method, the return Background is returning a class, but the build() method is expected to return a Widget instance. Perhaps this should be return Background().
In your kv, the indentation is incorrect. All indentations should be a multiple of the same number of spaces (typically 4). The indentation of Background is too large.
Your kv does not provide a rule for Background, so when Background() is returned, it will simply be an empty Widget. If you want to return Background(), you should have a <Background>: rule in the kv.
If your kv file is named my_browser.kv, then you do not need a build() method for your App class at all.
If your kv file is not named as above, then your build method can be return Builder.load_file("kv file name"), where kv file name is replaced by the correct name of your kv file.
The Floatlayout in your kv is misspelled. It should be FloatLayout.
Related
I've coded off and on as a hobby since the pandemic, and feel like I've gotten the hang of OOP and have began working on a basketball simulator. I've created a simulator uses a Player and Team class to simulate full basketball games, and now I'm looking to create a GUI using Kivy. I've watched dozens of tutorials, but I can't find anything that makes sense for what I already understand about Python.
I'd like to have a screen where the user can set attributes 1-99 for each player's offense and defense attribute using Kivy TextInput's, and have those values be assigned to each player.offense, so that when I hit "run," it runs my actual game script.
This is probably a stupid question and I just need to keep digging until I figure it out, but if anyone else had a similar mental barrier when learning Kivy, I'd love to hear how you made it make sense. Thanks!
Here is a minimal example showing how to assign a value to an attribute from a text input:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
kv = '''
BoxLayout:
text: your_textinput
orientation: 'vertical'
TextInput:
id: your_textinput
Button:
text: 'click'
on_press: app.clicked()
'''
class MyApp(App):
my_attribute = StringProperty()
def build(self):
return Builder.load_string(kv)
def clicked(self):
self.my_attribute = self.root.ids.your_textinput.text
print(self.my_attribute)
if __name__ == '__main__':
MyApp().run()
Probably self.root.ids.your_textinput.text is the most important part of it.
It goes as follow:
self is MyApp class
root is the main widget inside the app which is BoxLayout in this example
ids is a dictionary containing items that you assigned in your kv language code.
your_textinput: is the id we assigned to TextInput in kv language code
text is an attribute of the TextInput where the input is stored
Sometimes it gets trick to find which is root and which ids is under what object. You can use print with dir() and __class__ to detect it.
for example:
You can find if root has an ids attribute by using dir() on root:
print(dir(self.root))
You can also know what type of class is it by using:
print(self.root.__class__)
which give:
<class 'kivy.uix.boxlayout.BoxLayout'>
You can also use __doc__ if you added proper comments to your code.
print(self.__doc__)
Gives:
Main app class
You can read more about ids here:
https://kivy.org/doc/stable/api-kivy.uix.widget.html?#kivy.uix.widget.Widget.ids
Hope this is helpful and wish you enjoyable time using Kivy.
I am currently developing an embedded system with kivy.
Therefore, I found that if I make many screens, it slows down the program a lot.
Is there a good way to dynamically control screens so it does not slow down?
For instance, when I have 4 screens in ScreenManager like below,
MyScreenManager:
id: myscreenmanager
transition: FadeTransition()
SCRN_LOADING:
SCRN_IDLE:
SCRN_CALCULATING:
SCRN_RESULT:
Would it be possible to:
innitially load SCRN_LOADING first.
loads SCRN_IDLE and SCRN_CALCULATING while loading.
when loading is done, remove SCRN_LOADING screen object.
loads SCRN_RESULT while calculating.
when going back to idle, remove SCRN_RESULT screen object.
I am guessing this could improve performance.
Currently, the screen lags really hard. So I might have to restart the whole project using C if I can't solve the performance issue.
Please help me out!
I suppose you could declare your screens outside kv and then add them as required in your screen manager,In your kv
MyScreenManager:
id: myscreenmanager
transition: FadeTransition()
In your Window class:
from kivy.uix.screenmanager import ScreenManager, Screen
...
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.sm = self.ids.myscreenmanager
self.loading = Screen(name='SCRNLOADING')
self.idle = Screen(name='SCRN_IDLE')
self.calc = Screen(name='SCRN_CALCULATING')
self.sm.add_widget(self.loading)
self.set_idle()
def add_scrn(self):
self.sm.add_widget(self.idle)
self.sm.add_widget(self.calc)
self.sm.remove_widget(self.loading)
Im not really used to the Clock class but I'm sure you will need it here to load your screens correctly
How do I flip a (custom) kivy Widget from Python code? I've tried setting its height or width to negative value, but it actually rotates widget, ie flips both axes. The Rotate instruction obviously does the same. I'm aware there is a flip_horizontal() method of the Texture, but I don't have a slightest idea how to actually cause it to affect an existing widget rather than in-memory texture from eg Atlas.
If it helps, I use kivy 1.9.2 with Python 3.4.3.
UPD I tried Scale() to no effect.
event.actor.widget.img.canvas.before.add(PushMatrix())
event.actor.widget.canvas.before.add(Scale(x=2.0, origin=event.actor.widget.center))
event.actor.widget.img.canvas.after.add(PopMatrix())
event.actor.widget.canvas.ask_update()
It doesn't work either with or without PushMatrix/PopMatrix. The widget in question is a simple Widget subclass with stretchable image and a couple callbacks for size and position.
An easy way to achieve your goal is using a Scatter. Here is a full working example
from kivy.lang import Builder
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
import random
from kivy.graphics.transformation import Matrix
class MyBox(BoxLayout):
def later_(self, dt=None):
self.t.apply_transform(Matrix().scale(-1, 1.0, 1.0),
post_multiply=True,
anchor=self.to_local(*self.center))
Clock.schedule_once(self.later_, 1.0)
class TestApp(App):
def build(self):
Builder.load_string("""\
<MyBox>:
t: s
orientation: 'vertical'
Scatter:
id: s
do_scale: 0
do_rotate: 0
do_translation: 0,0
Label:
pos: s.pos
size: s.size
text: "The text below will keep changing using a delayed function..."
"""
)
mybox = MyBox()
Clock.schedule_once(mybox.later_, 1.0)
return mybox
if __name__ == '__main__':
TestApp().run()
How about a Scale instruction with a negative scaling?
If the widget also needs to take touch events, you'll need to modify its on_touch_down to transform them appropriately.
The goal is a screen which uses one of several images (randomly chosen upon each screen load) as a background.
The app contains the following:
class AnswerScreen(Screen):
bkgd = ""
def choose_bkgd(self):
self.bkgd = "{}.jpg".format(random.randint(0,8))
My kv file contains the following:
<AnswerScreen>
on_pre_enter: root.choose_bkgd()
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: root.bkgd
Unfortunately the background is always just a solid white.
I've added a print call to choose_bkgd(), and it always prints an acceptable file name, and I've also tried using on_enter: but there is no change. If I replace source: with a file name instead of root.bkgd the image displays correctly. This leads me to believe that the background is being generated before the function is being called to set the bkgd variable, but this confuses me as I thought the whole point of on_pre_enter was to execute code prior to the loading of the screen. The kivy docs haven't cleared this up for me. Any help is greatly appreciated.
Make bkgd a kivy property. This is essential to be able to bind to it and have things automatically update when it changes.
from kivy.properties import StringProperty
class AnswerScreen(Screen):
bkgd = StringProperty("")
...
I'm trying to use Kivy to display a background image, so I want the root widget to be the same size as the image. Currently, when I load the image from the kv file it appears as a small thumbnail in the bottom-left corner. The app window appears to be about the correct (full-scale) size, but hard to tell. Code below, any thoughts?
.kv file:
#:kivy 1.8.0
<BarBot_splash>:
BoxLayout:
size: image.size
Image:
id: image
source: 'MainMenu.png'
.py file:
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.widget import Widget
class BarBot_splash(Widget):
def on_touch_up(self, touch):
if touch.x < self.width/3:
#we touched the menu button
pass
elif touch.x > self.width/3*2:
#we touched the custom button
pass
else:
return False
class BarBot(App):
def build(self):
return BarBot_splash()
if __name__=='__main__':
BarBot().run()
In main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class BarBot_splash(BoxLayout): # subclass BoxLayout.. now it's inherently a Boxlayout
kv:
#:kivy 1.8.0
<BarBot_splash>: # I'm a BoxLayout...
Image:
id: image
source: 'MainMenu.png'
That should do the trick. The BoxLayout should take up the window. It's one child, the Image, should in turn take up the full size of the BoxLayout. Why? Well, someone correct me if I'm wrong, but I think it's because the size_hint property of the BoxLayout and the Image both default to (1, 1), which translates to: "Take up as much space in your parent as you can" or (100% width, 100% height). Though it may not be possible for a child to take up all of it's parents area if there are also other children in the parent, like if you had a few Images in the BoxLayout, or more than one BoxLayout in your app etc.. Setting a size_hint to (.5, .3) would mean take up (50% the width, 30% the height) of your parent/container, or available space.
BarBot_splash is just a widget, so it doesn't apply any position or size to its children, therefore the boxlayout (and thus its child image) have only the default position of (0, 0) and size of (100, 100).
Change BarBot_splash to a BoxLayout or other resizing layout and this will propagate correctly. You also don't need the size: image.size line, this does nothing.
Obviously very old question but I'm new to Kivy and just had to work through a very similar problem and there was very little help on the topic, so this is for future people like me:
I had the same problem but the image was also in a scatter widget. Solution is really simple, just frustrating to find. Hierarchy has to be as follows:
BoxLayout:
Scatter:
size: image.size
Image:
id: image
size: root.size