multiple widgets in Kivy - python

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.

Related

How to use slider as progress bar and volume control in kivy python using kv file not main python file

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 can't replace a Widget with a Screen in kivy

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

Outputting the input text in a new screen

Basically i'm trying to take some input from a user, perform some actions, and then output the result in a new screen (i'm thinking as the label of the new screen). I've managed to switch between screens but i cannot figure out how to output the input from the first screen to the second screen. I've tried to make the input data a global variable so i can assign to the text of the label of the output screen, but it didn't work. Here's my python file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen,ScreenManager
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen,ScreenManager
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
from kivy.properties import ColorProperty
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from plyer import filechooser
from kivymd.uix.dialog import MDDialog
Window.clearcolor = (1,1,1,1)
g_data = 'xstring'
class MainWindow(Screen):
def get_data(self):
global g_data
g_data = self.ids.user_input.text
class OutputScreen(Screen):
def ex(self):
self.ids.output_label.text = g_data
class mainApp(MDApp):
def __init__(self):
super().__init__()
def change_screen(self):
screemanager = self.root.ids['screenmanager']
screemanager.current = 'output'
def change(self):
self.change_screen()
if __name__ == '__main__':
mainApp().run()
and my kv file:
#:import utils kivy.utils
GridLayout:
cols:1
ScreenManager:
id: screenmanager
MainWindow:
id: main
name: 'main'
OutputScreen:
id: output
name: 'output'
<MainWindow>:
FloatLayout:
TextInput:
id: user_input
pos_hint:{"x" : 0.05, "top" : 0.9}
size_hint: 0.9, 0.37
Button:
pos_hint:{"top" : 0.51, "x" : 0.05}
size_hint: (None,None)
width : 150
height : 40
font_size : 23
text:'Submit'
on_release: app.change()
<OutputScreen>:
FloatLayout:
Label:
id: output_label
text: root.ex()
color: 0,0,0,1
Thank you very much.
I can't get your example to work, but you would need to do this:
g_data = '' # new global variable defined
class MainWindow(Screen):
def get_data(self):
global g_data # global goes here
g_data = self.ids.user_input.text
class OutputScreen(Screen):
def ex(self):
self.ids.output_label.text = g_data

Kivy create pulsing background

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

Kivy Digital Clock Issues

I'm trying to add a digital clock to my Kivy program, it seems to be having trouble.
Here is the .py:
import kivy
kivy.require('1.10.0')
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.stacklayout import StackLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
import time
class IntroScreen(Screen):
pass
class ContScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
backbone = Builder.load_file("main.kv")
class Status(FloatLayout):
_change = StringProperty()
_tnd = ObjectProperty(None)
def update(self, *args):
self.time = time.asctime()
self._change = str(self.time)
self._tnd.text = str(self.time)
print (self._change)
class XGApp(App):
time = StringProperty()
def update(self, *args):
self.time = str(time.asctime()) # + 'time'?
def build (self):
Clock.schedule_interval(self.update, 1)
return backbone
xApp = XGApp()
if __name__ == "__main__":
xApp.run()
and the .kv
<ContScreen>:
FloatLayout
size_hint: .1,.1
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: app.time
ContScreen is the title of the screen I want to show the clock on, it's served by a separate Builder (main.kv).
Any help would be appreciated! Been struggling with this clock for a few hours now. The trouble seems to be on the .kv side from what I can tell.
BONUS: If you want to go the extra mile, I also want to add a timer that counts down x amount on press of a button on the .kv. The x amount would be different depending on which button you press.
I have made a fork of the original kivydigitalclock here. It should be easier to use than the original. You can add it to your .kv file just as any other widget. For example, something like:
<ContScreen>:
FloatLayout
size_hint: .1,.1
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: app.time
DigitalClock:
pos_hint: {'right': 1.0, 'center_y': 0.5}
size_hint: (0.2, 0.2)
should work. Note that in your main .py file you will need to include:
from digitalclock.digitalclock import DigitalClock
(assuming that the digitalclock.py file is in a digitalclock folder)

Categories

Resources