I'm trying to create pulsing background in my app. Following this question Pulsing Background Color in Kivy
i've tried to make it work also, but for some reason it doesn't work. Here's my main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.core.window import Window
from kivymd.app import MDApp
from kivy.uix.image import Image
from kivy.animation import Animation
from kivy.clock import Clock
Window.size = (360,600)
class MyGridLayout(Screen):
def blink(self):
x = Clock.schedule_once(self.start_pulsing,2)
return x
def start_pulsing(self,*args):
anim = Animation(animated_color=(1,0,0,1))
anim.start(self)
anim.repeat = True
class mainApp(App):
def build(self):
return MyGridLayout()
if __name__ == '__main__':
mainApp().run()
And my main.kv file
<MyGridLayout>:
FloatLayout:
size: root.width, root.height
animated_color:(1,1,1,1)
canvas.before:
Color:
rgba :self.animated_color
Rectangle:
pos: self.pos
size: self.size
Any help will be much appreciated
A couple problems with your code:
The animated_color property in your kv is a property of the FloatLayout, but your python code references it as a property of MyGridLayout.
The anim.repeat = True will cause the Animation to be repeated, but after the first animation, the animated_color is already (1,0,0,1), so the repeated Animation will have no effect.
I don't see any code calling the blink() method to actually start the pulsing.
Here is a modified version of your code that reflects the above changes:
from kivy.app import App
from kivy.properties import ColorProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.core.window import Window
from kivy.animation import Animation
from kivy.clock import Clock
Window.size = (360,600)
class MyGridLayout(Screen):
animated_color = ColorProperty() # the color property to be animated
pulse_interval = 4 # the interval for pulsing
def blink(self):
x = Clock.schedule_once(self.start_pulsing,2)
return x
def start_pulsing(self,*args):
d = self.pulse_interval /2
anim = Animation(animated_color=(1,0,0,1), duration=d) + \
Animation(animated_color=(1,1,1,1), duration=d)
anim.repeat = True
anim.start(self)
class mainApp(App):
def build(self):
root = MyGridLayout()
root.blink() # star the pulsing
return root
if __name__ == '__main__':
mainApp().run()
And the modified main.kv:
<MyGridLayout>:
FloatLayout:
size: root.width, root.height
# animated_color:(1,1,1,1) # property needs to be attribute of MyGridLayout
canvas.before:
Color:
rgba :root.animated_color # reference the animated_color property of MyGridLayout
Rectangle:
pos: self.pos
size: self.size
Related
I want to create slider by file kv Not with the main Python file I was trying to program the code but it didn't turn out like I expected.
file py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.base import Builder
from kivy.core.spelling import Spelling
from kivy.core.audio import SoundLoader
from kivy.animation import Animation
class ManagImage(Screen):
s=SoundLoader.load("mm.mp3")
a=s.play()
lang=s.length
sl=s.get_pos()
def release(self,va):
self.sl = self.s.get_pos()
self.s.seek(int(va))
self.s.play()
self.slide.text=str((format((va/60),".2f")))
self.ids.lb.font_size=int(100)
class slider(App):
def build(self):
self.title = "slider"
slider().run()
File Kv
ManagImage:
slide:lb
BoxLayout:
orientation: "vertical"
padding:10
spacing:10
size:root.size
pos:root.pos
Label:
id : lb
Slider:
id : sd
pos_hint:{"right":1}
min: 0
max: root.lang
step: 1
value:root.sl
value_track:True
value_track_color:(150/255,60/255/10/255,1)
orientation: "horizontal"
on_value:root.release(self.value)
You can accomplish that by scheduling a method that fetches the audio position of the sound at specific intervals. Here is a modified version of your code that does that:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.screenmanager import Screen
from kivy.core.audio import SoundLoader
kv = '''
ManagImage:
slide:lb
BoxLayout:
orientation: "vertical"
padding:10
spacing:10
size:root.size
pos:root.pos
Label:
id : lb
Slider:
id : sd
pos_hint:{"right":1}
min: 0
max: root.lang
step: 1
value:root.sl
value_track:True
value_track_color:(150/255,60/255/10/255,1)
orientation: "horizontal"
# on_value:root.release(self.value) # not needed and causes an infinite loop
'''
class ManagImage(Screen):
sl = NumericProperty(0)
lang = NumericProperty(0)
def __init__(self, **kwargs):
super(ManagImage, self).__init__(**kwargs)
# start the sound playing
self.s = SoundLoader.load("test.mp3")
self.s.play()
self.lang = self.s.length
# schedule a method to update the self.sl every half second
self.sched = Clock.schedule_interval(self.get_audio_pos, 0.5)
def get_audio_pos(self, dt):
self.sl = self.s.get_pos()
class slider(App):
def build(self):
self.title = "slider"
return Builder.load_string(kv)
slider().run()
The get_audio_pos() method updates the sl property regularly and the Slider automatically updates since the kv sets its value to that Property.
The release() method was removed (along with its mention in kv) since it is not needed and will cause an infinite loop.
I have included the kv as a string in my code just for my own convenience. It can be used in a separate kv file just as well.
I'm a beginner at kivy, I have an fclass(Widget) that I want it to be a fclass(Screen), but when I tried to make the change all the screen messed up, the code generate some buttons with a for loop, I wish I coud do the same with a float layout, but I want the fclass to stay a screen since I'm building a multiscreen app.
Here is the .py file:
import kivy
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty, NumericProperty,ReferenceListProperty
from kivy.graphics.texture import Texture
from kivy.core.camera import Camera
from kivy.graphics import *
import time
import os
from pathlib import Path
#import cv2
import struct
import threading
import pickle
Builder.load_file('the.kv')
class fscreen(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.list_of_btns = []
def create(self):
self.h = self.height*0.9
for i in range(4):
self.h = self.h - self.height*0.1
self.btn = Button(text='button '+str(i), size=(self.width*0.4,self.height*0.05), pos=(self.width*0.3, self.h), on_press=self.press)
self.list_of_btns.append(self.btn)
self.add_widget(self.btn)
def press(self, instance):
print(instance.text)
def delete(self):
for btns in self.list_of_btns:
self.remove_widget(btns)
class theapp(App):
def build(self):
self.screenm = ScreenManager()
self.fscreen = fscreen()
screen = Screen(name = "first screen")
screen.add_widget(self.fscreen)
self.screenm.add_widget(screen)
return self.screenm
if __name__ == "__main__":
theapp = theapp() #
theapp.run()
The .kv file:
<fscreen>
Button:
text: 'create'
size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.1
on_press: root.create()
Button:
text: 'delete'
size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.2
on_press: root.delete()
How can I make the fclass a screen class without messing up everything ?
Thank you in advance
Seems to me that code should work, but it doesn't. A fix is to use size_hint instead of size in both your kv and py. So the kv could look like:
<fscreen>:
Button:
text: 'create'
size_hint: 0.4, 0.05
# size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.1
on_press: root.create()
Button:
text: 'delete'
size_hint: 0.4, 0.05
# size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.2
on_press: root.delete()
and in the create() method:
def create(self):
self.h = self.height * 0.9
for i in range(4):
self.h = self.h - self.height * 0.1
self.btn = Button(text='button ' + str(i), size_hint=(0.4, 0.05),
pos=(self.width * 0.3, self.h), on_press=self.press)
self.list_of_btns.append(self.btn)
self.add_widget(self.btn)
Your size in the kv and py were both just trying to do the size_hint anyway.
And, of course, your build() method must be adjusted:
def build(self):
self.screenm = ScreenManager()
self.fscreen = fscreen(name="first screen")
self.screenm.add_widget(self.fscreen)
return self.screenm
Other things to note:
You should use upper case for class names. Failure to do so can lead to errors in kv
You should consider using pos_hint instead of pos to allow better resizing of your App
I'm doing a tutorial about making a game, and still in the background period, making moving textures. But I just wonder why the wrapped problem fixed by %Window.width in the line self.cloud_texture.uvpos = {(self.cloud_texture.uvpos[0] + time_passed)%Window.width ,self.cloud_texture.uvpos[1]}
I see no problem when I just do self.cloud_texture.uvpos[0] + time_passed only, but the result told me the difference when it's changing the self.cloud_texture.uvpos[1] too, and starting to get some glitch when resizing window after few seconds.
Can someone give me an explanation so I can apply it to my other apps?
.py file
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.properties import ObjectProperty
from kivy.core.window import Window
class Background(Widget):
cloud_texture = ObjectProperty(None)
def __init__(self, **kwargs):
super().__init__(**kwargs)
#create texture
self.cloud_texture = Image(source="assets/cloud.png").texture
self.cloud_texture.wrap = "repeat"
self.cloud_texture.uvsize = {Window.width / self.cloud_texture.width, -1}
def scroll_textures(self,time_passed):
self.cloud_texture.uvpos = {(self.cloud_texture.uvpos[0] + time_passed)%Window.width ,self.cloud_texture.uvpos[1]}
texture = self.property("cloud_texture")
texture.dispatch(self)
from kivy.clock import Clock
class MainApp(App):
def on_start(self):
Clock.schedule_interval(self.root.ids.background.scroll_textures, 1/60)
pass
if __name__ == "__main__":
MainApp().run()
.kv file
FloatLayout:
Background:
id: background
canvas.before:
Rectangle:
size: self.size
pos: self.pos
source: "assets/sky.png"
Rectangle:
size: self.width, 138
pos: self.pos[0], self.pos[1] + self.height - 138
texture: self.cloud_texture
You can find the images I'm using here
I am new to python front-end. Currently i am stuck with integrating 2 python kivy programs.
Each of them have different widget. One is asynchronous image loading and one is clock widget.
Can anyone help me to integrate this multiple widgets in a sigle python file. I am adding my python codes below. please help me.
Asynchronus image loading
from kivy.app import App
from kivy.uix.image import AsyncImage
from kivy.lang import Builder
Builder.load_string('''
<CenteredAsyncImage>:
allow_stretch: True
keep_ratio: True
size_hint_y: None
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
height: dp(800)
mipmap: True
''')
class CenteredAsyncImage(AsyncImage):
pass
class TestAsyncApp(App):
def build(self):
img = 'edited_background.jpg'
return CenteredAsyncImage(source=img)
if __name__ == '__main__':
TestAsyncApp().run()
Clock Widget
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.base import Builder
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from kivy.core.window import Window
import time
class Time(Label):
def updateTime(self,*args):
self.text = time.asctime()
class TimeApp(App):
def build(self):
t=Time()
Clock.schedule_interval(t.updateTime,1)
return(t)
TimeApp().run()
I need to display both in a single window and clock should be in the top right most corner.
Here is a way to do that:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from centeredasyncimage import CenteredAsyncImage
from timelabel import Time
theroot = Builder.load_string('''
RelativeLayout:
CenteredAsyncImage:
source: 'img.jpg'
size_hint: 0.25, 0.25
pos_hint: {'x': 0, 'top': 1.0}
Time:
id: time
size_hint: 0.25, 0.25
pos_hint: {'right': 1.0, 'top': 1.0}
''')
class TheApp(App):
def build(self):
# schedule the start of the clock
Clock.schedule_once(self.start_time_updates)
return theroot
def start_time_updates(self, dt):
t = self.root.ids.time
# schedule the clock update every second
Clock.schedule_interval(t.updateTime,1)
if __name__ == '__main__':
TheApp().run()
This assumes that the CenteredAsyncImge is defined in a file named centeredasyncimage.py and Time is defined in a file named timelabel.py.
In those files, the code that is used to run an App needs to be protected from running when the file is imported. That is done using if __name__ == '__main__':. So, I have modified those files slightly:
timelabel.py:
from kivy.uix.label import Label
import time
class Time(Label):
def updateTime(self,*args):
self.text = time.asctime()
if __name__ == '__main__':
from kivy.app import App
from kivy.clock import Clock
class TimeApp(App):
def build(self):
t=Time()
Clock.schedule_interval(t.updateTime,1)
return(t)
TimeApp().run()
and centeredasyncimage.py:
from kivy.uix.image import AsyncImage
from kivy.lang import Builder
Builder.load_string('''
<CenteredAsyncImage>:
allow_stretch: True
keep_ratio: True
size_hint_y: None
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
height: dp(800)
mipmap: True
''')
class CenteredAsyncImage(AsyncImage):
pass
if __name__ == '__main__':
from kivy.app import App
class TestAsyncApp(App):
def build(self):
img = 'edited_background.jpg'
return CenteredAsyncImage(source=img)
TestAsyncApp().run()
If you want to update the image source for the CenteredAsyncImage, you can just modify the file containing the App as:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty
from centeredasyncimage import CenteredAsyncImage
from timelabel import Time
theroot = Builder.load_string('''
RelativeLayout:
CenteredAsyncImage:
id: casi
source: 'img.jpg' # default image (this is optional)
size_hint: 0.25, 0.25
pos_hint: {'x': 0, 'top': 1.0}
Time:
id: time
size_hint: 0.25, 0.25
pos_hint: {'right': 1.0, 'top': 1.0}
''')
class TheApp(App):
img_source = StringProperty() # property to hold image source
def build(self):
self.bind(img_source=self.set_casi_source) # bind source property
Clock.schedule_once(self.start_time_updates)
return theroot
def set_casi_source(self, app, val, *args):
# this sets the image source
self.root.ids.casi.source = val
def start_time_updates(self, dt):
t = self.root.ids.time
Clock.schedule_interval(t.updateTime,1)
if __name__ == '__main__':
TheApp().run()
The img_source StringProperty will contain the source for the CenteredAsyncImage. The call to self.bind arranges for any change to the img_source to trigger a call to set_casi_source(), which sets the source for the CenteredAsyncImage. Note that setting the img_source inside the build() method will fail, since it uses ids and they are not setup yet in the build() method. So, any time after the App is built, just changing the img_source property will change the CenteredAsyncImage.
I have very little experience with Python and Kivy. I am helping my little nephew with his quest to build a game using the two. We are stuck at something that seems simple.
Consider following code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint
from kivy.graphics import Color, Ellipse, Rectangle
from kivy.uix.floatlayout import FloatLayout
import math
class Fly(Widget):
pass
class Stick(Widget):
pass
class FlyBox(Widget):
pass
class GameArea(FloatLayout):
pass
class FlyApp(App):
def build(self):
gameArea = GameArea()
flyBox = FlyBox()
flyBox.canvas.add(Rectangle(pos_hint={'x': 0, 'y': .3}, size_hint=(1, .3)))
flyBox.canvas.add(Color(1, 0, 0))
gameArea.add_widget(flyBox)
return gameArea
if __name__ == '__main__':
FlyApp().run()
it produces following output:
What we were trying to achieve was:
The FlyBox's height should be 1/3rd the height of the GameArea's height.
The FlyBox's width should be same as GameArea's width.
The FlyBox's x coordinate should be 0 and its y coordinate should be 1/3rd the height of GameArea.
i.e. if the game area were to be divided into 3 equal sized horizontal bands, the FlyBox should be the middle band. And as the size of game area changes (due to resizing of window), the FlyBox's size and position should change relatively.
We are trying to avoid using a .kv file and instead do everything in Python.
You only need to use size_hint_y property to set the correct height (1/3rd the parent height) and pos_hint property to position it in the center.
Using kivy languaje:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
kv_text = '''
<GameArea>:
Widget:
id: flybox
size_hint_y: 1/3
pos_hint: {'x': 0, 'center_y': .5}
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
'''
class GameArea(FloatLayout):
pass
class FlyApp(App):
def build(self):
Builder.load_string(kv_text)
return GameArea()
if __name__ == '__main__':
FlyApp().run()
Output: