I need to access the height of a widget after it is created. However, whenever I tried to access my_widget.height, it returns the default height of 100 rather than the actual height.
Retrieving self.height inside the on_touch_down definition of the my_widget class works though.
My problem is really best described in the following code.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class Layout(BoxLayout):
# the following yields the correct height of Layout,
# which is the same as the height of the Window
def on_touch_down(self, touch):
print("inside Layout via on_touch_down:", self.height)
class MyApp(App):
def build(self):
l = Layout()
# However, accessing the height here yields the
# the default height 100
print("inside MyApp:", l.height)
return l
if __name__ == "__main__":
MyApp().run()
I spent hours reading different parts of the API doc and the guides on the Kivy website, but couldn't quite find what I missed.
In the build() method the application has not yet been built so the widget has its default value, so you must obtain that information a moment later, for this there are the following options:
Use App.on_start():
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class Layout(BoxLayout):
pass
class MyApp(App):
def build(self):
l = Layout()
return l
def on_start(self):
print(self.root.height)
if __name__ == "__main__":
MyApp().run()
Use Clock.schedule_once():
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
class Layout(BoxLayout):
pass
class MyApp(App):
def build(self):
l = Layout()
Clock.schedule_once(self.after_build)
return l
def after_build(self, dt):
print(self.root.height)
if __name__ == "__main__":
MyApp().run()
Related
I always see people creating big structures in .kv files. Sometimes they write the kv in a variable in the .py file.
Here I'm trying to create a widget with kv language in .py file but it doesn't work.
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivymd.uix.textfield import MDTextFieldRect
class App(MDApp):
def build(self):
print("building app")
self.screen = Screen()
return self.screen
def on_start(self):
print("starting app")
kv = '''
MDTextFieldRect:
'''
e = Builder.load_string(kv)
self.screen.add_widget(e)
if __name__ == "__main__":
app = App()
app.run()
And I know that I can do it another way but I want to learn how to do it like this because I have troubles creating some widget with python when it works in kv language.
Here is a working example of how I could do it but I need to learn another way.
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivymd.uix.textfield import MDTextFieldRect
class App(MDApp):
def build(self):
print("building app")
self.screen = Screen()
return self.screen
def on_start(self):
print("starting app")
self.screen.add_widget(MDTextFieldRect())
if __name__ == "__main__":
app = App()
app.run()
I am trying to create a simple programe that animates my label widget to desired position upon clicking on the kivy window. Just trying to experiment with inheritance to access all the elements in the parent element.
ani is the parent class and transit is the child class. I am trying to access the label attribute in transit via inheritance. But this throws error.
from kivy.app import App
from kivy.uix.label import Label
from kivy.animation import Animation
from kivy.uix.widget import Widget
class transit(ani,Widget):
def __init__(self,**kwargs):
ani.__init__(self,**kwargs)
def on_touch_down(self,touch):
val = 5
print(touch.x,touch.y)
self.val +=10
animation = Animation(x = touch.x,y =touch.y,font_size=self.val,d=2,t='in_out_quad')
animation.start(self.parent.label)
class ani(App):
def __init__(self,**kwargs):
self.label = Label(text='increase')
def build(self):
return transit()
root = ani()
root.run()
I believe you are trying to use inheritance with the wrong class. If you want to move a Label, you need to put the Label in a container and make sure the size of the Label does not fill the container. Since the position of the Label is controlled by its container, you need to use inheritance with the container. Here is a simple code, similar to yours, that uses a FloatLayout as the container:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.animation import Animation
class MyFloatLayout(FloatLayout):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
val = 5
label = App.get_running_app().label
animation = Animation(x = touch.x,y =touch.y,font_size=val,d=2,t='in_out_quad')
animation.start(label)
return super(MyFloatLayout, self).on_touch_down(touch)
class ani(App):
def build(self):
root = MyFloatLayout()
self.label = Label(text='increase', size_hint=(None, None), size=(100,40))
root.add_widget(self.label)
return root
if __name__ == '__main__':
ani().run()
This code uses inheritance to define a new MyFloatLayout class that adds a new on_touch_down() method that does the animation. Note that the new on_touch_down() also calls super(MyFloatLayout, self).on_touch_down(touch). Unless there is a specific reason for not doing that, you normally want to call the super method in an inherited method.
I am trying to change to another screen by swiping the screen. I've tried carousel but it seems that it only works with images, so I've tried detecting a swipe motion and changing the screen after it has been detected.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.carousel import Carousel
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
class HomeScreen(Screen):
def on_touch_move(self, touch):
if touch.x < touch.ox: # this line checks if a left swipe has been detected
MainApp().change_screen(screen_name="swipedhikr_screen") # calls the method in the main app that changes the screen
class ImageButton(ButtonBehavior, Image):
pass
class LabelButton(ButtonBehavior, Label):
pass
class SettingsScreen(Screen):
pass
class SwipeDhikrScreen(Screen):
pass
#def quit_verification():
# pop = Popup(title="verification", content=Label(text= "Are you sure?"))
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
def change_screen(self, screen_name):
# get the screen manager from the kv file
screen_manager = self.root.ids["screen_manager"]
screen_manager.transition.direction = "up"
screen_manager.current = screen_name
def quit_app(self):
MainApp().stop()
MainApp().run()
I got an attribute error: "None type object has no attribute 'ids'"
MainApp().change_screen(screen_name="swipedhikr_screen")
This line creates a new instance of MainApp, which doesn't have any widgets and therefore naturally fails when you try to access them.
Use the existing instance of MainApp, i.e. the one that you're actually running, via MainApp.get_running_app().
Also you are not correct that Carousel works only with images.
I'm runing "Kivy" on Windows 10. When I use "Images" in Kivy App... it returns Blank screen..
My code is Following(Code files and Images are in same folder)
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.image import Image
class Game(Widget):
def __init__(self):
super(Game, self).__init__()
self.background = Image(source='backGround.jpg')
self.size = self.background.size
self.add_widget(self.background)
self.add_widget(Image(source='bird.jpg'))
class GameApp(App):
def build(self):
return Game()
if __name__ == "__main__":
GameApp().run()
Please Someone point out Mistake... I'll be greatful... Regards
I'm trying to make a button which uses an image from URL.
icon= str('https://cdn2.iconfinder.com/data/icons/flat-ui-icons-24-px/24/eye-24-256.png')
self.add_widget(ImageButton(source=(icon), size=(100,100), size_hint=(0.1, 0.1), on_press=callback, pos_hint={"x":0.90, "top":1.0}))
class ImageButton(ButtonBehavior, Image):
pass
It shows as an white image for some reason. Could anyone help me please?
As eyllanesc comments, you must use AsyncImage subclass to load the image asynchronously from the server. Otherwise, the image will not be available when you instantiate the widget.
On the other hand, the code you show in your comment;
icon = AsyncImage(source='https://.../icon.png')
self.add_widget(ImageButton(source=(str(icon)))
is also incorrect, You are trying to pass to source (StringPropery) an instance of AsyncImage. The simple solution to that is to inherit from AsyncImage and not from Image:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import AsyncImage
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.window import Window
Window.clearcolor = (1, 1, 1, 1)
class ImageButton(ButtonBehavior, AsyncImage):
pass
class MainWindow(BoxLayout):
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
icon = 'https://cdn2.iconfinder.com/data/icons/flat-ui-icons-24-px/24/eye-24-256.png'
self.add_widget(ImageButton(source=icon))
class Test(App):
def build(self):
return MainWindow()
if __name__ == "__main__":
Test().run()