Media Player Pause Button - kivy

Good day friends.
I am new in kivy and kivymd. I am coding for an audio media player using kivy and kivymd. The play button works well but the pause button is where my challenge is. I checked the kivy documentation but no way. I need your assistance guys. Below is the code.
.KV File:
MDIconButton:
id: pla
icon: 'play-outline'
opacity: 1
on_press: root.play()
MDBoxLayout:
orientation: 'vertical'
MDIconButton:
id: pau
icon: 'pause'
opacity: 0
on_press: root.on_pause()
.PYFile:
def play(self):
self.sound = SoundLoader.load('1Republic -2late 2 apologise.mp3')
self.sound.play()
def on_pause(self):
self.sound.pause()

The kivy.core.audio.Sound has some strange quirks. First, there is no pause() method, so you must implement that method yourself. You can implement that capability using get_pos(), seek(), stop() and play(). Another quirk is that the seek() only works after calling play(), and there must be a delay between calling play() and calling seek().
Here is an example code that implements a pause capability:
from kivy.clock import Clock
from kivy.core.audio import SoundLoader
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
kv = '''
Player:
MDIconButton:
id: pla
icon: 'play-outline'
on_press: root.play()
MDBoxLayout:
orientation: 'vertical'
MDIconButton:
id: pau
icon: 'pause'
on_press: root.pause()
MDIconButton:
id: res
icon: 'cog-play'
on_press: root.resume()
'''
class Player(MDBoxLayout):
def play(self):
self.sound = SoundLoader.load('1Republic -2late 2 apologise.mp3')
self.sound_pos = 0
self.sound.play()
def pause(self):
self.sound_pos = self.sound.get_pos()
self.sound.stop()
def resume(self):
self.sound.play()
Clock.schedule_once(self.do_seek) # seems to be required to get seek to work
def do_seek(self, dt):
self.sound.seek(self.sound_pos)
class TestApp(MDApp):
def build(self):
return Builder.load_string(kv)
TestApp().run()

Related

When creating a widget with a button, how to specify an ID?

So I already make an expanding list when pressing a button, the problem is that I canĀ“t find I way to add an icon in the right part(as the sample one) of the ListItem
Code:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.uix.screen import MDScreen
from kivymd.uix.list import OneLineRightIconListItem
from kivymd.uix.list.list import IconRightWidget
Window.size = (300, 500)
navigation_helper = """
<DietScreen>:
Screen:
MDBoxLayout:
orientation: 'vertical'
padding: ("5dp", "65dp" , "5dp", "5dp")
pos_hint: {"top": 1}
MDScrollView:
MDList:
id: box
OneLineRightIconListItem:
id: hola
text: 'testitem'
on_press:
IconRightWidget:
icon: "dots-vertical"
MDRaisedButton:
text: "Nueva Dieta"
md_bg_color: "white"
text_color: "black"
font_size: 16.2
pos_hint: {"right": 1, "bottom": 1}
on_press: root.buttonClicked()
Screen:
MDNavigationLayout:
ScreenManager:
id: scr
DietScreen:
"""
class DietScreen(MDScreen):
def buttonClicked(self):
newButt = OneLineRightIconListItem(text='Button')
self.ids.box.add_widget(newButt)
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(navigation_helper)
return screen
DemoApp().run()
I tried to specify an id to the ListItem created, and in the same method after addind the ListItem, add an IconRightWidget with an icon determined, but it results in an error.
Replace your:
newButt = OneLineRightIconListItem(text='Button')
With:
newButt = OneLineRightIconListItem(IconRightWidget(icon='dots-vertical'), text="Button")

KivyMD, MDFloatingActionButton: correct placement

I've been trying to use floating action buttons alongside FileChooser:
import kivy
kivy.require("2.1.0")
from kivy.utils import platform
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivymd.app import MDApp
from kivymd.uix.tab import MDTabsBase
from kivymd.icon_definitions import md_icons
import os
USERPATH = os.path.expanduser("~")
if platform == "android":
from android.storage import primary_external_storage_path
from android.storage import secondary_external_storage_path
from android.permissions import request_permissions, Permission
USERPATH = primary_external_storage_path()
request_permissions(
[Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE]
)
KV = '''
#:kivy 2.1.0
#:set dark_gray (.5, .5, .5, 1)
MDBoxLayout:
orientation: "vertical"
MDTabs:
id: ps_tabs
TabList:
id: ps_tab_list
icon: "folder"
FileChooserListView:
id: ps_filechooser
canvas.before:
Color:
rgba: dark_gray
Rectangle:
size: self.size
pos: self.pos
MDFloatingActionButton:
id: fc_playdir
icon: "folder"
pos_hint: {"center_x": .4, "center_y": .5}
MDFloatingActionButton:
id: fc_playfile
icon: "file"
pos_hint: {"center_x": .6, "center_y": .5}
TabDetails:
id: ps_tab_details
icon: "book"
MDScrollView:
'''
class TabList(FloatLayout, MDTabsBase):
"""The engaged power supplies tab."""
class TabDetails(FloatLayout, MDTabsBase):
"""The engaged power supply details tab."""
class Ron(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
self.theme_cls.primary_palette = "Gray"
self.theme_cls.material_style = "M3"
if platform != "android":
self.root.ids.ps_tabs.lock_swiping = True
self.root.ids.ps_filechooser.rootpath = USERPATH
if __name__ == "__main__":
Ron().run()
Mouse clicks, as well as taps, shoot right through the buttons and into the FileChooser, no matter what I do. I tried placing the buttons into their own box layout, tried moving them up and down the widget tree. Nothing helps, while the buttons remain visible. Besides, on visiting the second tab, one can see two thick black button footprints. Something's very wrong and I can't think of anything else to try.

Animating objects via ID in kivy

I am trying to animate a graphic in kivy. Since all my inputs will be coming from the keyboard, I need to have object references in python, however I still want to set up the widgets in the kv file. To do this I found the only way to trigger anything from python was using IDs. However when trying to start an animation via ID the object doesn't move. Printing the x coordinate shows a change, although I don't see it move.
Here is my main.py:
import threading
import time
import keyboard
from kivy.app import App, ObjectProperty
from kivy.uix.screenmanager import Screen, ScreenManager, NoTransition
from kivy.uix.floatlayout import FloatLayout
from kivy.animation import Animation, AnimationTransition
class MainScreen(Screen):
pass
class OtherScreen(Screen):
pass
def left_animate(object):
anim = Animation(x=object.x - 40, transition='in_back')
anim.start(object)
class RootWidget(FloatLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.screenman = ScreenManager()
self.screenman.add_widget(MainScreen(name="main"))
self.screenman.add_widget(OtherScreen(name="other"))
self.add_widget(self.screenman)
x = threading.Thread(target=self.keyboard_thread)
x.start()
def keyboard_thread(self):
print("Thread started")
while True:
if keyboard.is_pressed('h'):
self.key_event('h')
elif keyboard.is_pressed('j'):
self.key_event('j')
elif keyboard.is_pressed('left'):
self.left_pressed()
def left_pressed(self):
if self.screenman.current == 'main':
anim = Animation(x = 40)
print(self.ids.main.ids.img_ok.x)
anim.start(self.ids.main.ids.img_ok)
def key_event(self, key):
if key == 'h':
self.screenman.current = "main"
else:
self.screenman.current = "other"
class TestApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
TestApp().run()
and this is the .kv file:
<RootWidget>:
ScreenManager:
MainScreen:
id: main
OtherScreen:
id: other
<MainScreen>:
canvas.before:
Color:
rgba: 0, 0, 0, 1
canvas:
Rectangle:
pos: root.pos
size: root.size
Image:
id: img_ok
source: '../graphics/icons8-abstimmung-80.png'
pos: 200, 200
<OtherScreen>:
Button:
text: 'Go to main screen'
on_press: root.manager.current = 'main'
The first problem is that you are building two ScreenManagers. One is built in the __init__() method of RootWidget. The other is being built by kv when it evaluates the <RootWidget>: rule in your .kv file. Both of those ScreenManagers fill the RootWidget and one obscures the other. I believe that your Animation is moving the Image widget, but it is underneath and not visible.
I suggest that you start fixing this by eliminating:
self.screenman = ScreenManager()
self.screenman.add_widget(MainScreen(name="main"))
self.screenman.add_widget(OtherScreen(name="other"))
self.add_widget(self.screenman)
from the __init__() method. That will force additional changes to your code.

Kivy >> On Press method triggered twice

For some reason the On Press event for the instance of Word_button is being triggered twice. The code below demonstrates this.
To repeat the problem.
run the code below
click on the "CREATE LIST OF WORD" button. This create a list of buttons. Each button has Boolean property if the word is correct or not.
then click on the word buttons. When clicking the button, the print statements print the correct boolean variable and the text of the button.
Problem:
The print commands are run twice.
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
from kivy.properties import (NumericProperty, BooleanProperty)
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.boxlayout import MDBoxLayout
kv = '''
<Word_button#MDRaisedButton>:
pos_hint: {'center_x': .5}
size_hint: 1, 1
font_size: "16sp"
on_press: self.check_word()
<Words_Box#MDBoxLayout>:
pos_hint: {'center_x': .5}
size_hint: 1, 1
Screen:
id: spelling_screen
name: "spelling_screen"
MDBoxLayout:
orientation: 'vertical'
padding: dp(15)
spacing: dp(10)
MDLabel:
text: 'Words'
Words_Box:
id: words_box
orientation: 'vertical'
padding: dp(15)
spacing: dp(10)
MDRaisedButton:
text: 'CREATE LIST OF WORDS'
on_release: root.ids.words_box.add_word_buttons()
'''
class Word_button(MDRaisedButton):
correct = BooleanProperty()
def check_word(self):
print('Answer is ', self.correct)
print('Button Text is ', self.text)
class Words_Box(MDBoxLayout):
def add_word_buttons(self):
app = MDApp.get_running_app()
words = ['$WORD 1', 'WORD 2', 'WORD 3']
for word in words:
correct = False
if '$' in word:
correct = True
word = word[1:]
btn = Word_button(text=word, correct=correct)
self.add_widget(btn)
class RootScreen(Screen):
def __init__(self, **kwargs):
super(RootScreen, self).__init__(**kwargs)
class Main(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_string(kv)
def build(self):
return self.screen
Main().run()
This was resolved by not naming the kv file main.kv.

Using builder in Kivy

I want to create a simple app that has GUI with a button that allows me to vibrate an android phone. Im using a .kv file for the layout and the Builder in my .yp file
.py file:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from plyer import vibrator
class AndroidApp(GridLayout):
def vibrate(self):
vibrator.vibrate()
kv = Builder.load_file("android_app.kv")
class MainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MainApp().run()
.kv file:
#:import utils kivy.utils
<AndroidApp>:
FloatLayout:
canvas.before:
Color:
rgb: utils.get_color_from_hex("#ffffff")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 1
cols: 2
Label:
text:"Android Vibrate"
Button:
text:"Android Vibrate"
on_press:
root.vibrate()
When I try to run the app, I get the following error:
enter image description here
This should be straightforward app but somehow I find a way to make it crash. The android_app.py & .kv files are in the same folder. Any ideas why the window wont be created? I aprreciate any help.
Thanks,
Alex
You have to return the main class, not the result from building. Here I'm using Builder.load_string() for convenience, and not importing player, but otherwise the only substantive change is that I changed return kv to return AndroidApp()
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
KV = '''
#:import utils kivy.utils
<AndroidApp>:
FloatLayout:
canvas.before:
Color:
rgb: utils.get_color_from_hex("#ffffff")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 1
cols: 2
Label:
text:"Android Vibrate"
Button:
text:"Android Vibrate"
on_press:
root.vibrate()
'''
class AndroidApp(GridLayout):
def vibrate(self):
vibrator.vibrate()
Builder.load_string(KV)
class MainApp(App):
def build(self):
return AndroidApp()
if __name__ == "__main__":
MainApp().run()

Resources