Animation subclass - python

in Animation class, how to set d = 0.4, t = 'in_out_quad' by default? Can I use subclass for that?
from kivy.app import App
from kivy.lang import Builder
from kivy.animation import Animation
KV = """
Label
text: '123'
on_touch_down: app.test()
"""
class MyApp(App):
def build(self):
self.root = Builder.load_string(KV)
def test(self):
a = Animation(x = 500, d = .2, t = 'in_out_quad')
a.start(self.root)
MyApp().run()
Tried something like this (with no success):
from kivy.app import App
from kivy.lang import Builder
from kivy.animation import Animation
KV = """
Label
text: '123'
on_touch_down: app.test()
<MyAnim>:
d: .2
t: 'in_out_quad'
"""
class MyAnim(Animation):
pass
class MyApp(App):
def build(self):
self.root = Builder.load_string(KV)
def test(self):
a = MyAnim(x = 500)
a.start(self.root)
MyApp().run()
I just want not to write the values of the arguments d and t many times if they are the same in my project

I haven't tested this, but I think you could just put those defaults in your class definition:
class MyAnim(Animation):
def __init__(self, **kw):
super(MyAnim, self).__init__(d = .2, t = 'in_out_quad', **kw)
Of course, if you use MyAnim and specify another t= or d=, you will get an error.
That error can be avoided by only adding the default values if they are not already specified:
class MyAnim(Animation):
def __init__(self, **kw):
if 'd' not in kw:
kw['d'] = 0.2
if 't' not in kw:
kw['t'] = 'in_out_quad'
super(MyAnim, self).__init__(**kw)

Related

It is necessary to transfer to the SecondScreen class, the text that the button_press function returns from the ScreenMain class

Please help, I'm trying to make an application for a child to learn the alphabet, I'm just learning programming and working with classes.
I need to pass to the SecondScreen class the text that the button_press function returns from the ScreenMain class.
`
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from itertools import chain
from kivy.uix.screenmanager import ScreenManager, Screen
class ScreenMain(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.alphabet = [chr(i) for i in chain(range(1040, 1046), range(1025, 1026), range(1046, 1069), range(32, 33),
range(1069, 1072))]
gr = GridLayout(cols=5, padding=[35], spacing=3)
for i in self.alphabet:
gr.add_widget(Button(text=i, on_press=self.button_press))
self.add_widget(gr)
def button_press(self, instance):
self.manager.transition.direction = 'left'
self.manager.current = 'second_screen'
print(instance.text) # I output to the console, everything is ok
return instance.text
class SecondScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
get = ScreenMain.button_press # I'm trying to pass a letter from a function to a class button_press
layout = GridLayout(cols=5, rows=5, padding=[35], spacing=10)
layout.add_widget(Button(
text=str(get))) # Trying to create a button on the second page with the text of the letter pressed on the first screen
self.add_widget(layout)
def _on_press_button_new_layout(self, *args):
self.manager.transition.direction = 'right'
self.manager.current = 'main_screen'
class MyApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(ScreenMain(name='main_screen'))
sm.add_widget(SecondScreen(name='second_screen'))
return sm
if __name__ == '__main__':
MyApp().run()
`

How do I easily and cleanly update an image in Kivy widget from python?

Firstly, this is a large piece of code so I will try to simplify it for the sake of this question. I have a Kivy Language script which has a root widget, with an action bar and boxlayout. The code's general structure goes a bit like this (I do not believe this is required for answering this question but here it is anyway): Root > MenuBarWidg > BoxLayout > Image + Other buttons/labels....
Now, here is what my widget looks like in kivy (for the boxlayout):
<DisplayPhoto>:
Image:
id: image_display
allow_strech: True
#StringProperty in the class
source: root.image_path
Button:
Inside my python script:
class DisplayPhoto(BoxLayout):
image_path = StringProperty()
def __init__(self, **kwargs):
super(DisplayPhoto, self).__init__(self)
self.image_path = 'reload.png'
#this is called from another class on a button press
def update(self):
self.image_path = 'new_image_path.png'
Upon calling update in the python script, nothing happens. I have tried print(self.image_path) which displays new_image_path.png, but it is also a string - not a kivy object.
I have tried things such as updating the source by calling the id etc but got nowhere with that. Any help is appreciated!
I guess the problem is how you call that update() method.
Please refer to the following code
One way of doing it:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
Config.set('graphics', 'position', 'custom')
Config.set('graphics', 'left', 0)
Config.set('graphics', 'top', 0)
Builder.load_file('main.kv')
class MainView (BoxLayout):
image_source = StringProperty()
def __init__(self, **kwargs):
super(MainView, self).__init__(**kwargs)
self.image_source = 'pic1.png'
class AnotherClass(BoxLayout):
def change_image(self):
app = App.get_running_app()
app.root.ids['my_image'].source = 'pic2.png'
class ImageChangeApp (App):
def build(self):
return MainView()
if __name__ == '__main__':
ImageChangeApp().run()
main.kv:
<MainView>:
Image:
id: my_image
source: root.image_source
AnotherClass:
<AnotherClass>:
Button:
text: 'Change picture'
on_release: root.change_image()
Another way of doing it is using event dispatcher
main.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
Config.set('graphics', 'position', 'custom')
Config.set('graphics', 'left', 0)
Config.set('graphics', 'top', 0)
Builder.load_file('main.kv')
class MainView (BoxLayout):
pass
class DisplayPhoto(BoxLayout):
image_path = StringProperty()
def __init__(self, **kwargs):
super(DisplayPhoto, self).__init__(**kwargs)
self.image_path = 'pic1.png'
self.register_event_type('on_image_path')
def on_image_path(self, instance, val):
print(instance)
print(val)
self.image_path = val
class AnotherClass(BoxLayout):
def change_image(self):
app = App.get_running_app()
app.root.ids['display_photo'].dispatch('on_image_path', self, 'pic2.png')
class ImageChangeApp (App):
def build(self):
return MainView()
if __name__ == '__main__':
ImageChangeApp().run()
main.kv
<MainView>:
DisplayPhoto:
id: display_photo
AnotherClass:
<DisplayPhoto>:
Image:
source: root.image_path
<AnotherClass>:
Button:
text: 'Change picture'
on_release: root.change_image()

Kivy KV File Custom Property

I cannot for the life of me figure out how to pass a custom property on a custom widget via the KV file. My application is a simple grid that contains a Button() and TestWidget(). TestWidget() has a StringProperty() test_property that doesn't seem to get the data from the KV file as seen by the print statement on init. Here's some quick straight forward code as an example.
Thanks.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string("""
<TestWidget>:
<TestGrid>:
Button:
TestWidget:
test_property: 'Test Property'
""")
class TestWidget(Widget):
test_property = StringProperty()
def __init__(self, **kwargs):
super(TestWidget, self).__init__(**kwargs)
print('Test OUTPUT:', self.test_property)
class TestGrid(GridLayout):
pass
class MyApp(App):
def build(self):
return TestGrid()
MyApp().run()
I think I figured it out. Kivy doesn't pass anything to the objects. I learned this at https://kivy.org/docs/api-kivy.properties.html.
I use the on_ to do what needs to be done. There is a big difference between Kivy Objects and Python Objects.
Here's an example of a custom BoxLayout;
class KivyInput(BoxLayout):
text_test = StringProperty()
def __init__(self, **kwargs):
super(KivyInput, self).__init__(**kwargs)
self.orientation = 'horizontal'
self.label = Label()
self.text_input = TextInput(multiline=False)
self.add_widget(self.label)
self.add_widget(self.text_input)
def on_text_test(self, instance, value):
self.label.text = value
def remove(self):
self.clear_widgets()
Try printing it on the upcoming frame, instead of in the initiation of the object.
After the object is created, you can access the properties.
You do that with Clock.
Like this:
from kivy.clock import Clock
class TestWidget(Widget):
test_property = StringProperty()
def __init__(self, **kwargs):
super(TestWidget, self).__init__(**kwargs)
Clock.schedule_once(self.after_init) # run method on next frame
def after_init(self,dt):
print('Test OUTPUT:', self.test_property)

Kivy - Update a label with sensor data?

New to kivy, and OOP.
I'm trying to update a label in kivy with data I pull from a temp sensor. The code that pulls in the sensor data is in labeltempmod. I created a function getTheTemp() that is called every second. In the function I try to assign the text of the label via Label(text=(format(thetemp)), font_size=80). The program ignores this. What am I doing wrong here?
#This is a test to see if I can write the temp to label
import labeltempmod
import kivy
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
def getTheTemp(dt):
thetemp = labeltempmod.readtemp()
Label(text=(format(thetemp)), font_size=80)
print thetemp
class LabelWidget(BoxLayout):
pass
class labeltestApp(App):
def build(self):
# call get_temp 0.5 seconds
Clock.schedule_interval(getTheTemp, 1)
return LabelWidget()
if __name__ == "__main__":
labeltestApp().run()
Here is the kivy language file:
<LabelWidget>:
orientation: 'vertical'
TextInput:
id: my_textinput
font_size: 80
size_hint_y: None
height: 100
text: 'default'
FloatLayout:
Label:
id: TempLabel
font_size: 150
text: 'Temp Test'
Thanks.
Sorry but you never update something You are just creating another label
Try this:
class LabelWidget(BoxLayout):
def __init__(self, **kwargs):
super(LabelWidget, self).__init__(**kwargs)
Clock.schedule_interval(self.getTheTemp, 1)
def getTheTemp(self, dt):
thetemp = labeltempmod.readtemp()
self.ids.TempLabel.text = thetemp
print thetemp
class labeltestApp(App):
def build(self):
return LabelWidget()
if __name__ == "__main__":
labeltestApp().run()
Update : for your last request, I think the best way to do that is:
...
class LabelWidget(BoxLayout):
def __init__(self, **kwargs):
super(LabelWidget, self).__init__(**kwargs)
self.Thetemp = None
Clock.schedule_interval(self.getTheTemp, 1)
def getTheTemp(self, dt):
if self.Thetemp is None:
self.thetemp = labeltempmod.readtemp()
else:
self.thetemp = labeltempmod.readtemp(self.theTemp)
self.ids.TempLabel.text = str(self.thetemp)

Kivy: is it possible to trigger events with class level (not instance) Properties?

Consider following code. I would like to update multiple widget instances when prefix changes. As it is the same for all the instances it seems efficient to store/update it only once on class level (so that when instance does not have its own self.prefix, it will automatically refer to class level prefix attribute)
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import StringProperty
import random
kivy_lang = '''
<MainWidget>:
Button:
id: my_button
text: 'increase indice'
<MyLabel>:
on_prefix: self.text = self.prefix +':'+ self.indice
on_indice: self.text = self.prefix +':'+ self.indice
'''
class MyLabel(Label):
prefix = StringProperty('1')
indice = StringProperty('0')
pass
class MainWidget(BoxLayout):
def __init__(self, **kwargs):
super(MainWidget, self).__init__(**kwargs)
self.my_label1 = MyLabel()
self.my_label2 = MyLabel()
self.add_widget(self.my_label1)
self.add_widget(self.my_label2)
self.ids.my_button.bind(on_press=self.my_method)
def my_method(self,*args,**kwargs):
MyLabel.prefix = str(random.randint(0,9))
self.my_label1.indice = str(int(self.my_label1.indice) + 1)
# my_label2 would also be updated if its 'indice' got changed as below
# self.my_label2.indice = str(int(self.my_label2.indice) + 2)
class MyApp(App):
def build(self):
Builder.load_string(kivy_lang)
return MainWidget()
if __name__ == '__main__':
MyApp().run()
As from the python side this seems right, from Kivy side it looks like kivy has problem recognising when prefix got changed (my_label1 only gets updated because indice was also updated and on_indice is triggered).
Is there a way to get 'class level Property' prefix change to trigger on_prefix ?
I don't think this is possible directly, but you could mimic that functionality with AliasProperty and another property stored, say, on App. As long as the instance of MyLabel hasn't changed prefix, the value set for App is used (and automatically updated). Once prefix is set on an instance, _my_prefix is not None, and will be used to retrieve the value for prefix.
Change the <MyLabel> rule to
<MyLabel>:
_prefix: app.prefix
text: self.prefix +':'+ self.indice
And change the python code to
class MyLabel(Label):
indice = StringProperty('0')
_prefix = StringProperty('')
_my_prefix = StringProperty(None)
def get_prefix(self):
if self._my_prefix is None:
return self._prefix
else:
return self._my_prefix
def set_prefix(self, value):
self._my_prefix = value
prefix = AliasProperty(get_prefix, set_prefix, bind=('_prefix', '_my_prefix'))
[...]
def my_method(self,*args,**kwargs):
App.get_running_app().prefix = str(random.randint(0,9))
self.my_label1.indice = str(int(self.my_label1.indice) + 1)
if int(self.my_label1.indice) == 2:
self.my_label2.prefix = 'changed'
[...]
class MyApp(App):
prefix = StringProperty('1')

Categories