After the song is playing use seek to position the song to cur_pos.
A small example:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.properties import BooleanProperty
kv= """
SoundTestBoxLayout:
orientation: 'vertical'
Label:
text: 'Audio test'
font_size: 20
BoxLayout:
size_hint_y: None
height: dp(48)
Button:
text: 'Play'
on_release: root.play()
Button:
text: 'Pause'
on_release: root.pause()
disabled: root.paused
Button:
text: 'Stop'
on_release: root.stop()
Label:
text:
"""
class SoundTestBoxLayout(BoxLayout):
paused = BooleanProperty(False)
def __init__(self, **kwargs):
self.sound = SoundLoader.load('music/PinkPanther60.wav')
self.song_position = None
super().__init__(**kwargs)
def play(self):
self.sound.play()
if self.paused:
self.sound.seek(self.song_position)
self.paused = False
def pause(self):
self.song_position = self.sound.get_pos()
self.sound.stop()
self.paused = True
def stop(self):
self.sound.stop()
self.paused = False
class SoundTestApp(App):
def build(self):
return Builder.load_string(kv)
SoundTestApp().run()
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5c4065bd-ee6b-474e-8719-f2cbc09aa186%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e92f4dd.1c69fb81.92374.9e95SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
😁
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vg_cobknDLg4_ybdAQO7xDwwrq%3DHQXxWZ4BPPgsmvJFcw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9342be.1c69fb81.86085.6781SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Here are a few points to consider.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vi0ByBsG7KT2oTCi1zS__ru175LGgFvAT5mhnKn1%2BTFEg%40mail.gmail.com.
Here is an example:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.core.audio import SoundLoader
from glob import glob
kv = """
<AudioPlayer>:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: 48
Button:
text: 'prev'
on_release: root.previous()
Button:
text: 'next'
on_release: root.next()
Button:
text: 'play'
on_release: root.play()
Button:
text: 'stop'
on_release: root.stop()
Label:
text: root.song_name
font_size:30
BoxLayout:
orientation: 'vertical'
Label:
text: 'Audio File Player'
font_size: 30
AudioPlayer:
"""
class AudioPlayer(BoxLayout):
song_name = StringProperty('No Song Selected')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.songs = glob('music/*.wav') # change to appropriate directory and *.mp3
self.song_index = 0
self.stop_pressed = False
def play(self):
if self.song:
if self.song.state == 'play':
self.stop_pressed = True # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
self.song_name = self.songs[self.song_index]
def next(self):
self.song_index = min(self.song_index + 1, len(self.songs) -1)
self.play()
def previous(self):
self.song_index = max(self.song_index -1, 0)
self.play()
def stop(self):
if self.song:
self.stop_pressed = True
self.song.stop()
self.song = None
def song_end(self, *args):
print('song end')
if not self.stop_pressed:
self.next()
self.stop_pressed = False
class AudioPlayerApp(App):
def build(self):
return Builder.load_string(kv)
AudioPlayerApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vi0ByBsG7KT2oTCi1zS__ru175LGgFvAT5mhnKn1%2BTFEg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e95ec1a.1c69fb81.80d2f.c649SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Thanks for your kinds words. Best of health to you and your family… and to us all.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViVm2FUaARWXdg9aobeH6Xb%2B5DT-nY9HQB1i5U-CGfQmg%40mail.gmail.com.
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.core.audio import SoundLoader
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.image import Image
from mutagen.id3 import ID3, APIC
from mutagen import File
from mutagen.mp3 import MP3
from glob import glob
Builder.load_string('''
<MyWidget>:
Label:
text: 'Image_Display'
pos_hint: {'center_x':.5, 'center_y':.9}
<MyImage>:
source: root.img()
size: self.size
pos: self.pos
Button:
text: 'previous'
size_hint: .2, .1
pos_hint:{'center_x':.1, 'center_y': .1}
on_press: root.previous()
Button:
text: 'play'
size_hint: .2, .1
pos_hint:{'center_x':.3, 'center_y': .1}
on_press: root.play()
Button:
text: 'pause'
size_hint: .2, .1
pos_hint:{'center_x':.5, 'center_y': .1}
on_press: root.pause()
disabled: root.paused
Button:
text: 'next'
size_hint: .2, .1
pos_hint:{'center_x':.7, 'center_y': .1}
on_press: root.next()
Button:
text: 'stop'
size_hint: .2, .1
pos_hint:{'center_x':.9, 'center_y': .1}
on_press: root.stop()
MyWidget:
''')
class MyImage(FloatLayout):
#pass
paused = BooleanProperty(False)
def __init__(self, **kwargs):
super(MyImage, self).__init__(**kwargs)
self.song = None
#self.songs = glob('music/*.wav') # change to appropriate directory and *.mp3
self.songs = glob(path to file)
self.song_index = 0
self.stop_pressed = False
self.paused = False
def img(self):
self.album = File(path to file)
self.destination = path to file # for image saving
self.cover = self.album['APIC:'].data
with open(self.destination, 'wb') as img:
img.write(self.cover)
self.mp3_img = Image(source = self.destination)
self.add_widget(self.mp3_img)
def play(self):
if self.song:
if self.song.state == 'play':
self.stop_pressed = True # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
#self.song.loop = True # it loops current song which is playing
self.song_name = self.songs[self.song_index]
if self.paused:
self.song.seek(self.song_position)
self.paused = False
def pause(self):
self.song_position = self.song.get_pos()
self.song.stop()
self.paused = True
def next(self):
self.song_index = min(self.song_index + 1, len(self.songs) - 1)
self.play()
def previous(self):
self.song_index = max(self.song_index - 1, 0)
self.play()
def stop(self):
if self.song:
self.stop_pressed = True
self.song.stop()
self.song = None
def song_end(self, *args):
print('song end')
if not self.stop_pressed:
self.next()
self.stop_pressed = False
class MyWidget(FloatLayout):
pass
class ImageDisplay(App):
def build(self):
return MyImage()
ImageDisplay().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e95ec1a.1c69fb81.80d2f.c649SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
I added pause to the original example I created:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.core.audio import SoundLoader
from glob import glob
kv =
"""
<AudioPlayer>:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: 48
Button:
text: 'prev'
on_release: root.previous()
Button:
text: 'next'
on_release: root.next()
Button:
text: 'play'
on_release: root.play()
Button:
text: 'pause'
on_release: root.pause()
Button:
text: 'stop'
on_release: root.stop()
Label:
text: root.song_name
font_size:30
BoxLayout:
orientation: 'vertical'
Label:
text: 'Audio File Player'
font_size: 30
AudioPlayer:
"""
class AudioPlayer(BoxLayout):
song_name = StringProperty('No Song Selected')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.songs = glob('music/*.wav') # change to appropriate directory and *.mp3
self.song_index = 0
self.stop_pressed =
False
self.song_position = 0
self.paused = False
def play(self):
if self.paused:
self.song.play()
self.song.seek(self.song_position)
self.paused = False
return
if self.song:
if self.song.state == 'play':
self.stop_pressed = True # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
self.song_name = self.songs[self.song_index]
def next(self):
self.song_index = min(self.song_index + 1, len(self.songs) -1)
self.play()
def previous(self):
self.song_index = max(self.song_index -1, 0)
self.play()
def stop(self):
if self.song:
self.stop_pressed = True
self.paused = False
self.song.stop()
self.song = None
def pause(self):
if self.paused:
return
if self.song:
self.paused = True
self.song_position = self.song.get_pos()
self.song.stop()
self.paused = True
def song_end(self, *args):
print('song end')
if self.paused:
return
if not self.stop_pressed:
self.next()
self.stop_pressed = False
class AudioPlayerApp(App):
def build(self):
return Builder.load_string(kv)
AudioPlayerApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vi%3D9iBomTLz67%2BnKhtjYXonrgX44rGWGD%3DCwTuxsU01oA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9b13d9.1c69fb81.f347e.beeeSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
I tried it again with .mp3, it is all working.
Here it is again, all I changed was using mp3 files, instead of wave files.
None
self.songs = glob('music/*.mp3') # change to appropriate directory and *.mp3
self.song_index = 0
self.stop_pressed = False
self.song_position = 0
self.paused = False
def play(self):
if self.paused:
self.song.play()
self.song.seek(self.song_position)
self.paused = False
return
if self.song:
if self.song.state == 'play':
self.stop_pressed = True # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
self.song_name = self.songs[self.song_index]
def next(self):
self.song_index = min(self.song_index + 1, len(self.songs) -1)
self.play()
def previous(self):
self.song_index = max(self.song_index -1, 0)
self.play()
def stop(self):
if self.song:
self.stop_pressed = True
self.paused = False
self.song.stop()
self.song = None
def pause(self):
if self.paused:
return
if self.song:
self.paused = True
self.song_position = self.song.get_pos()
self.song.stop()
self.paused = True
def song_end(self, *args):
print('song end event')
if self.paused:
return
if not self.stop_pressed:
self.next()
self.stop_pressed = False
class AudioPlayerApp(App):
def build(self):
return Builder.load_string(kv)
AudioPlayerApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgbOJOm2qGDfKCdy%3Dw-f-v1-mEf%3DoPeBWyJthO6mPQ-3g%40mail.gmail.com.
Here is a slightly modified version. My original version did not have pause. As a result there were 2 boolean variables stop_pressed and pause_pressed used to manage state. I combined them here in to a kivy property called player_state. This state is used in the stop event handler, song_end(), to determine the appropriate action.
The player_state can be:
stop – the stop button has been pressed.
pause - the pause button has been pressed
ready – not paused or stopped.
The method on_player_state will print the state when it changes, this is for debug and will let you see what is going on. player_state needs to be a kivy property to create this event.
You can also use player_state to control the buttons in UI.
)
player_state = StringProperty('ready') # can be stop, pause, or ready (ready is not stop or pause)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.songs = glob('music/*.mp3') # change to appropriate directory and *.mp3
self.song_index = 0
self.song_position = 0
self.player_state = 'ready'
def play(self):
if self.player_state == 'pause':
self.song.play()
self.song.seek(self.song_position)
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
self.song_name = self.songs[self.song_index]
def next(self):
self.player_state = 'ready'
self.song_index = min(self.song_index + 1, len(self.songs) -1)
self.play()
def previous(self):
self.player_state = 'ready'
self.song_index = max(self.song_index -1, 0)
self.play()
def stop(self):
if self.song:
self.player_state = 'stop'
self.song.stop()
self.song = None
def pause(self):
if self.player_state == 'pause':
return
if self.song:
self.player_state = 'pause'
self.song_position = self.song.get_pos()
self.song.stop()
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop':
self.next()
self.player_state = 'ready'
def on_player_state(self, *args): # this is for debug - it prints out the state when it changes
print(f'state: {self.player_state}')
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9c6589.1c69fb81.377c9.ce8aSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9c6589.1c69fb81.377c9.ce8aSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Raja,
That’s interesting. Do some tests. For the songs that don’t property resume from pause, do they always report their position as zero?
Check the meta-data, you might be able to see if it is some particular combination of bit-rate or compression settings that is causing this problem.
I have not experienced this issue. It would be a function of the underlying audio decoder.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vjuz%3DgODrJ8e2JTRk77O_u5o4z%2BaS52oo_tYrokii3x-g%40mail.gmail.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9c7a62.1c69fb81.fd627.1ba8SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
It looks like the songs are properly reporting their position when paused.
Test that the seek command is working properly with these songs.
From: Raja Ramesh
Sent: Sunday, April 19, 2020 10:06 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
yes, position is Zero after resuming from pause.... i have attached screenshot of log for the same. Now how to solve this. just to clarify .... we need to use third party libraries like Mutagen, id3reader.... to check metadata of song ?

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VhtTiUiscRkaS2VFA%2BjXZxNMX5pazo0L2%2B26x8%2BCbyi4w%40mail.gmail.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9c8b13.1c69fb81.3c425.3f52SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Seek does not return a value.
If you do a seek with one of your problem files, does the seek work. To seek the song must be playing. You can use get_pos() after a seek to see if the seek worked.
If you want, send me one of your problem files, I can do some tests as well.
From: Raja Ramesh
Sent: Sunday, April 19, 2020 10:57 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot, value of seek is saying None for all songs which are resuming from pause also not resuming from pause.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Viiot-1FwukE1ouHz11rNqZH6AUPCzCqTOoBAPHotcv2w%40mail.gmail.com.

https://superuser.com/questions/893494/mp3-file-seek-is-bugged
It looks like a problem with the way your file is encoded.
The seek() method has no effect.
The problem can be detected by getting the length of the song. The length is coming back as -1. This suggests the length meta-data is not correct.
Do you have another encoder you could use? Or perhaps find an encoder that can correct meta-data.
You could disable the pause button for content with a length of -1, or use to re-encode the data from within your app if you find a solution.
For a progressbar, load the song, play the song, get the length. Set max on the progress bar to be int(length). Use Clock.schhedule_once, the set up a schedule to update the progress bar every .1 seconds. Cancel the schedule on pause, and resume when play is pressed. On stop cancel the schedule and reset the progressbar.
Give it a shot. Post a small example if you run into trouble
From: Raja Ramesh
Sent: Sunday, April 19, 2020 10:53 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
i have attached sample file.
i am not sure how to perform seek. Also i implemented code for progress bar in the app but not sure how to implement seek. similar like below screenshot.

Thanks,
Raja
On Sun, Apr 19, 2020 at 11:31 PM Elliot Garbus <elli...@cox.net> wrote:
Seek does not return a value.
If you do a seek with one of your problem files, does the seek work. To seek the song must be playing. You can use get_pos() after a seek to see if the seek worked.
If you want, send me one of your problem files, I can do some tests as well.
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vj1thCb1GEv0tzr19KzGvhC6Ys9nK9inSegr%2BwVCFT%3Dcg%40mail.gmail.com.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.uix.progressbar import ProgressBar
from kivy.properties import BooleanProperty
from glob import glob
kv= """
SoundTestBoxLayout:
FloatLayout:
Button:
text: 'Play'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.3, 'center_y': 0.1}
on_release: root.play()
Label:
id: val
pos_hint:{'center_x':0.07,'center_y':0.55}
Button:
text: 'Pause'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.4, 'center_y': 0.1}
on_release: root.pause()
disabled: root.paused
Button:
text: 'Stop'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.6, 'center_y': 0.1}
on_release: root.stop()
Button:
text: 'Prev'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.2, 'center_y': 0.1}
on_release: root.previous()
Button:
text: 'next'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.5, 'center_y': 0.1}
on_release: root.next()
# below code is for slider
Slider:
id: slider
min: 0.0
max: 1.0
value: 0.2
on_value: root.set_volume(self.value)
value_track: True
value_track_color: (1,0,0,1)
orientation: "vertical"
size_hint_x: None
width: "48dp"
Label:
text: str(round(slider.value * 100))
pos_hint:{'center_x':0.05, 'center_y':.9}
"""
class SoundTestBoxLayout(FloatLayout):
paused = BooleanProperty(False)
player_state = StringProperty('ready') # can be stop, pause, or ready (ready is not stop or pause)
def __init__(self, **kwargs):
#self.song_position = None
self.song = None
self.song_index = 0
self.stop_pressed = False
self.song_position = 0
self.paused = False
self.player_state = 'ready'
self.songs = glob(r'C:\music\*.mp3')
super().__init__(**kwargs)
def play(self):
if self.player_state == 'pause':
self.song.play()
self.song.seek(self.song_position)
print('seek position is:- %s' % (self.song.seek(self.song_position)))
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
if self.song:
self.song.volume = 0.2
self.song.play()
self.song_name = self.songs[self.song_index]
self.event = Clock.schedule_interval(self.play_status, 0.1)
def play_status(self, _):
if self.song:
self.text = str(self.song.get_pos())
mins = self.song.get_pos() / 60
self.ids.val.text = str(round(mins,2))
self.progress = ProgressBar(max = mins)
self.progress = ProgressBar(max= self.song._get_length())
#self.progress.value = mins
self.progress.value = self.song.get_pos() if self.progress.value < self.song._get_length() else 0
self.add_widget(self.progress)
else:
self.text = "play"
Clock.unschedule(self.event)
def set_volume(self, volume):
self.volume= volume
if self.song:
self.song.volume = self.volume
def stop(self):
if self.song:
self.player_state = 'stop'
self.song.stop()
self.song = None
def pause(self):
if self.player_state == 'pause':
return
if self.song:
self.player_state = 'pause'
print('song name paused is:- %s' %(self.song_name))
self.song_position = self.song.get_pos()
print('current position after pausing the song is:- %s' % (self.song_position))
self.song.stop()
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop':
self.next()
self.player_state = 'ready'
def on_player_state(self, *args): # this is for debug - it prints out the state when it changes
print(f'state: {self.player_state}')
class SoundTestApp(App):
def build(self):
return Builder.load_string(kv)
SoundTestApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9dba63.1c69fb81.9d204.057fSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Here you go…
You were creating multiple progress bars on top of each other. You want one progress bar, and to change its value and min.
Some other small enhancements.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.uix.progressbar import ProgressBar
from kivy.properties import BooleanProperty
from glob import glob
kv =
"""
SoundTestBoxLayout:
FloatLayout:
Button:
text: 'Play'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.3, 'center_y': 0.1}
on_release: root.play()
Label:
id: val
text: '00:00'
size_hint: None, None # adding
size: self.texture_size
pos_hint:{'x': .1, 'center_y':0.55}
Button:
text: 'Pause'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.4, 'center_y': 0.1}
on_release: root.pause()
disabled: root.paused
Button:
text: 'Stop'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.6, 'center_y': 0.1}
on_release: root.stop()
Button:
text: 'Prev'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.2, 'center_y': 0.1}
on_release: root.previous()
Button:
text: 'next'
size_hint: 0.1,0.07
pos_hint:{'center_x': 0.5, 'center_y': 0.1}
on_release: root.next()
# below code is for slider
BoxLayout:
ProgressBar:
id:pb
Slider:
id: slider
min: 0.0
max: 1.0
value: 0.2
on_value: root.set_volume(self.value)
value_track: True
value_track_color: (1,0,0,1)
orientation: "vertical"
size_hint_x: None
width: "48dp"
Label:
text: str(round(slider.value * 100))
pos_hint:{'center_x':0.05, 'center_y':.9}
"""
class SoundTestBoxLayout(FloatLayout):
paused = BooleanProperty(False)
player_state = StringProperty('ready') # can be stop, pause, or ready (ready is not stop or pause)
def __init__(self
, **kwargs):
# self.song_position = None
self.song = None
self.song_index = 0
self.stop_pressed = False
self.song_position = 0
self.paused = False
self.player_state = 'ready'
self.songs = glob('music\*.mp3')
self.event = None
super().__init__(**kwargs)
def play(self):
if self.player_state == 'pause':
self.song.play()
self.song.seek(self.song_position)
print('seek position is:- %s' % (self.song.seek(self.song_position)))
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.volume = 0.2
self.song.play()
self.player_state = 'ready'
self.song_name = self.songs[self.song_index]
self.event = Clock.schedule_interval(self.play_status, 0.1)
def play_status(self, _):
if self.player_state == 'pause':
return
if self.song:
t = int(self.song.get_pos())
mins = int(t / 60)
secs = t % 60
self.ids.val.text = f'{mins:02}:{secs:02}'
self.ids.pb.max = int(self.song.length)
self.ids.pb.value = int(self.song.get_pos())
def set_volume(self, volume):
self.volume = volume
if self.song:
self.song.volume = self.volume
def stop(self):
if self.event:
self.event.cancel() # this is the preferred method of stopping the timer
if self.song:
self.ids.pb.value = 0
self.ids.val.text = '00:00'
self.player_state = 'stop'
self.song.stop()
self.song = None
def pause(self):
if self.player_state == 'pause':
return
if self.song:
self.player_state = 'pause'
print('song name paused is:- %s' % (self.song_name))
self.song_position = self.song.get_pos()
print('current position after pausing the song is: %s' % (self.song_position))
self.song.stop()
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop':
self.next()
self.player_state = 'ready'
def on_player_state(self, *args): # this is for debug - it prints out the state when it changes
print(f'state: {self.player_state}')
class SoundTestApp(App):
def build(self):
return Builder.load_string(kv)
SoundTestApp().run()
From: Raja Ramesh
Sent: Monday, April 20, 2020 10:37 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
I appended progress bar and volume code. Need your inputs for below points,
1. progress bar color is not disappearing after completion of song. it's over ridding on top of it for next song.
2. i am not able to add seek code to progress bar.(i mean play from the drag position of progress bar.)
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vgqk9NzLXrT1fTuse_zS0HKfcJS0M23rdOBft2ELbJMMA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9df668.1c69fb81.fdea2.373eSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
How to perform drag / seek to certain position on progress bar and continue playing from that dragged / seek position. similar to attached gif file. it is for video but i need to perform same functionality for songs.
Replace the ProgressBar with a slider. When the value of the slider changes (on_value: ) do a seek.
I’ll take a look at the Pb behavior on next song.
When the next song is detected in the end_song method, the pb needs to be reset.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vj7MUE34b-O7z2D-ziTEwW%3Db%3DodNa7JBHj0vwSw2UqPbA%40mail.gmail.com.
You do want to use a Slider, but I realized you can not use on_value. The on_value event will be firing while the song in playing. The program is using the slider value like it did the progress bar, updating during song play. To avoid this I have created a new class called TouchSlider, that extends slide and adds an on_move event. It only does the seek during when a touch is moving the slider.
There is some work to do to adjust the allow a seek from stop.
from kivy.properties import StringProperty
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.uix.slider import Slider
from glob import glob
kv = """
<AudioPlayer>:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: 48
Button:
text: 'prev'
on_release: root.previous()
Button:
text: 'next'
on_release: root.next()
Button:
text: 'play'
on_release: root.play()
Button:
text: 'pause'
on_release: root.pause()
Button:
text: 'stop'
on_release: root.stop()
BoxLayout:
Label:
size_hint_x:.1
text: root.song_time
TouchSlider:
id:pos_slider
on_move: root.go_to_pos(self.value)
Label:
size_hint_x:.1
text: root.song_time_end
Label:
text: root.song_name
font_size:30
BoxLayout:
orientation: 'vertical'
Label:
text: 'Audio File Player'
font_size: 30
AudioPlayer:
"""
class TouchSlider(Slider):
def __init__(self, **kwargs):
self.register_event_type('on_release')
self.register_event_type('on_press')
self.register_event_type('on_move')
super().__init__(**kwargs)
def on_press(self):
pass
def on_release(self):
pass
def on_move(self):
pass
def on_touch_down(self, touch):
super().on_touch_down(touch)
if self.collide_point(*touch.pos) and self.disabled is False:
self.dispatch('on_press')
return True
def on_touch_move(self, touch):
super().on_touch_move(touch)
if self.collide_point(*touch.pos) and self.disabled is False:
self.dispatch('on_move')
return True
def on_touch_up(self, touch):
super().on_touch_up(touch)
if touch.grab_current == self:
self.dispatch('on_release')
return True
class AudioPlayer(BoxLayout):
song_name = StringProperty('No Song Selected')
player_state = StringProperty('ready') # can be stop, pause, or ready (ready is not stop or pause)
song_time_end = StringProperty('00:00')
song_time = StringProperty('00:00')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.schedule = None
self.songs = glob('music/*.mp3') # change to appropriate directory and *.mp3
self.song_index = 0
self.song_position = 0
self.player_state = 'ready'
print(self.songs)
def play(self):
if self.player_state == 'pause':
self.song.seek(self.song_position)
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song_name = self.songs[self.song_index]
print(f'{self.song_name} Loaded, the length is: {self.song.length}')
self.song_time_end = self.pos_to_min_sec(self.song.length)
self.schedule = Clock.schedule_interval(self._play_status, 0.1)
def _play_status(self, _):
if self.player_state == 'pause':
return
if self.song:
self.song_time = self.pos_to_min_sec(self.song.get_pos())
self.ids.pos_slider.max = int(self.song.length)
self.ids.pos_slider.value = int(self.song.get_pos())
def go_to_pos(self, p):
if self.song:
self.song.seek(p)
@staticmethod
def pos_to_min_sec(seconds):
t = int(seconds)
mins = int(t / 60)
secs = t % 60
return f'{mins:02}:{secs:02}'
def next(self):
self.player_state = 'ready'
self.song_index = min(self.song_index + 1, len(self.songs) - 1)
def previous(self):
self.player_state = 'ready'
if self.schedule:
self.schedule.cancel()
if self.song:
self.ids.pos_slider.value = 0
self.song_time = '00:00'
self.player_state = 'stop'
self.song.stop()
self.song = None
def pause(self):
if self.player_state == 'pause':
return
if self.song:
self.player_state = 'pause'
self.song_position = self.song.get_pos()
self.song.stop()
print(f'The Song Paused at: {self.song_position}')
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop':
self.next()
self.player_state = 'ready'
def on_player_state(self, *args): # this is for debug - it prints out the state when it changes
print(f'state: {self.player_state}')
class AudioPlayerApp(App):
def build(self):
return Builder.load_string(kv)
AudioPlayerApp().run()
From: Elliot Garbus
Sent: Tuesday, April 21, 2020 6:41 AM
To: kivy-...@googlegroups.com
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9ef7f6.1c69fb81.51cb2.9853SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Added a few refinements:
RelativeLayout: # Put the label in a relative layout to prevent wiggling, as time changes
size_hint_x: .1
Label:
text: root.song_time
pos_hint: {'x': .02, 'center_y': .5}
TouchSlider:
id:pos_slider
on_move: root.go_to_pos(self.value)
on_release: root.go_to_pos(self.value)
def resume_from_pause(self):
self.schedule = Clock.schedule_interval(self._play_status, 0.1)
def play(self):
if self.player_state == 'pause':
self.resume_from_pause()
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song_name = self.songs[self.song_index]
print(f'{self.song_name} Loaded, the length is: {self.song.length}')
self.song_time_end = self.pos_to_min_sec(self.song.length)
self.schedule = Clock.schedule_interval(self._play_status, 0.1)
def _play_status(self, _):
if self.player_state == 'pause':
return
if self.song:
self.song_time = self.pos_to_min_sec(self.song.get_pos())
self.ids.pos_slider.max = int(self.song.length * 10) # Increased slider granularity for smoother movement
self.ids.pos_slider.value = int(self.song.get_pos() * 10)
def go_to_pos(self, p):
p = p / 10 # slider value is postion * 10
if self.song:
self.song_time = self.pos_to_min_sec(p)
if self.song.state == 'play':
self.song.seek(p)
else:
self.player_state = 'pause'
self.song_position = p
self.song.seek(p)
self.song.stop()
@staticmethod
def pos_to_min_sec(seconds):
t = int(seconds)
mins = int(t / 60)
secs = t % 60
return f'{mins:02}:{secs:02}'
def next(self):
self.player_state = 'ready'
self.song_index = min(self.song_index + 1, len(self.songs) - 1)
def previous(self):
self.player_state = 'ready'
self.song_index = max(self.song_index - 1, 0)
def stop(self):
if self.schedule:
self.schedule.cancel()
if self.song:
self.ids.pos_slider.value = 0
self.song_time = '00:00'
self.player_state = 'stop'
self.song.stop()
def pause(self):
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9f1ea1.1c69fb81.1460.8f42SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5e9f1ea1.1c69fb81.1460.8f42SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
I made a few changes to display the album art in the code below.
Read the comments.
from kivy.app import App
from kivy.core.audio import SoundLoader
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.widget import Widget
from mutagen import File
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from glob import glob
from kivy.uix.slider import Slider
import os
kv =
'''
Mywidget:
orientation: 'vertical'
Image: # Used an image, not a boxlayout
id: album_image
source: root.album_art # Used a property for the file name
allow_stretch: True
# size_hint: .3,.2 # Allow the art to fill the window)
album_art = StringProperty('img\image_NEW.jpg') # Added a property *** PUT DEFAULT IMAGE HERE ****
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.schedule = None
self.songs = glob(r'music\*.mp3')
self.song_index = 0
self.song_position = 0
self.player_state = 'ready'
print(self.songs)
def play(self):
if self.player_state == 'pause':
self.song.play()
self.song.seek(self.song_position)
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
self.song.play()
self.song_name = self.songs[self.song_index]
print(f'{self.song_name} Loaded, the length is: {self.song.length}')
self.song_time_end = self.pos_to_min_sec(self.song.length)
self.schedule = Clock.schedule_interval(self._play_status, 0.1)
self.get_image()
self.ids.album_image.reload() # reload required filename stays the same
def get_image(self):
# Below code is for mp3 image
self.destination = 'img\image_NEW.jpg' # for image saving
self.album = File(self.songs[self.song_index])
self.cover = self.album['APIC:'].data
with open(self.destination, 'wb') as img:
img.write(self.cover)
# img.close() the context manager closes the file
# self.mp3_img = Image(source=self.destination)
# self.add_widget(self.mp3_img)
self.album_art = 'img\image_NEW.jpg'
def _play_status(self, _):
if self.player_state == 'pause':
return
if self.song:
self.song_time = self.pos_to_min_sec(self.song.get_pos())
self.ids.pos_slider.max = int(self.song.length)
self.ids.pos_slider.value = int(self.song.get_pos())
def go_to_pos(self, p):
if self.song:
self.song.seek(p)
@staticmethod
def pos_to_min_sec(seconds):
t = int(seconds)
mins = int(t / 60)
secs = t % 60
return f'{mins:02}:{secs:02}'
def next(self):
self.player_state = 'ready'
self.song_index = min(self.song_index + 1, len(self.songs) - 1)
self.play()
def previous(self):
self.player_state = 'ready'
self.song_index = max(self.song_index - 1, 0)
self.play()
def stop(self):
if self.schedule:
self.schedule.cancel()
if self.song:
self.ids.pos_slider.value = 0
self.song_time = '00:00'
self.player_state = 'stop'
self.song.stop()
self.song = None
def pause(self):
if self.player_state == 'pause':
return
if self.song:
self.player_state = 'pause'
self.song_position = self.song.get_pos()
self.song.stop()
print(f'The Song Paused at: {self.song_position}')
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop':
self.next()
self.player_state = 'ready'
def on_player_state(self, *args): # this is for debug - it prints out the state when it changes
print(f'state: {self.player_state}')
# class MyImage(Screen):
# pass
class AudioImage(App):
def build(self):
return Builder.load_string(kv)
# return MyGrid()
if __name__ == '__main__':
AudioImage().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VjCUBrViowvaXPNTUztUMSPiYVQ42PPGR6yF1PVnZzyHw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea5a767.1c69fb81.ebf8f.0043SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Update what happens on song_end, now the song will stop after the last song.
def song_end(self, *args):
print(f'song end event, player_state: {self.player_state}')
if self.player_state == 'pause':
return
if not self.player_state == 'stop' and self.song_index != len(self.songs) -1: # check if we are not at the last song…
self.next()
self.player_state = 'ready'
If you want the songs to play in a loop, update next() and previous() to loop instead of stopping at min or max.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViqP6nF6LOC324KHaPLAK0u3iXpsCRm%2Bo-eMAztrbO3Sw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea5c46c.1c69fb81.170fa.2111SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
The methods next() and pervious() are using min() and max() respectively as a clamp. You can go to the end, but no higher or no lower.
Now we want to reset the index when next hits the last song. Here iis an updated next(), use similar logic to update previous.
def next(self):
self.player_state = 'ready'
#self.song_index = min(self.song_index + 1, len(self.songs) - 1
if self.song_index < len(self.songs) -1:
self.song_index += 1
else:
self.song_index = 0
self.play()
Alternately you can use a ternary expression.
def next(self):
self.player_state = 'ready'
#self.song_index = min(self.song_index + 1, len(self.songs) - 1)
self.song_index = self.song_index + 1 if self.song_index < len(self.songs) - 1 else 0 # this is the same as the if else statement
self.play()
from kivy.app import App
Thanks,
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VhhtQCi7U%2B6smhVJyr7g3euDpLwe9W24epP_jZCSQRUFA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea6d207.1c69fb81.c2fd5.40ebSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
You could build a play list with a text input. If you do you would need to split the text on ‘/n’ to create a list of filenames, or songs. This would be rather error prone, so you would need some error checking (does the song exist in the library?). If you combined the text input with autocompletion hints it might be kind of interesting.
Depending on what you had in mind you could collect all of the music files in a directory, put the meta-data as labels on a RecycleView, and use a text input or spinner to next to each label to determine the order of the songs (or use a next or insert button). Or going further you could drag and drop the songs on to a playlist.
The issue with your code below was that in your play routine you were using self.text and expecting the text input text. In this context self is the BoxLayout. I gave the TextInput an id, and used that to access the text. If you provide a valid song file in the text input this will work.
from kivy.app import App
from kivy.core.audio import SoundLoader
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import StringProperty
kv =
'''
MyWidget:
orientation: 'vertical'
TextInput:
id: ti
hint_text: 'Enter Text'
Button:
text: 'play'
size_hint: .3,.2
pos_hint: {'center_x': .3, 'center_y': .1}
on_press: root.play()
'''
class MyWidget(BoxLayout):
text = StringProperty()
def play(self):
print(self.ids.ti.text)
self.song = SoundLoader.load(self.ids.ti.text)
self.song.play()
class Audio(App):
def build(self):
return Builder.load_string(kv)
Audio().run()
From: Raja Ramesh
Sent: Tuesday, April 28, 2020 10:48 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgocSmNp2EY6wGt79KKLofE2MG52fL98dyvd6Pms8D7sw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea87ac1.1c69fb81.c3a29.d6b8SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
You are clearing the list when you drag each file.
Try something like:
class DragDropMusic(App):
file_list = ListProperty()
def _on_file_drop(self, window, file_path):
print(file_path)
# self.file_list = [ ]
self.file_list.append(file_path.decode('utf-8'))
print(self.file_list)
This will give you a list of song files. I imagine you would want to convert the list of filenames to buttons with the song name or perhaps, the album art, artist, and song name… you can then create the Buttons and put them in a ScrollView.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vihi6G0BO1ivnfL8L8u1JADY2eXnroSJyrg0QEhSq%2BnBA%40mail.gmail.com.

from kivy.app import App from kivy.lang import Builder from kivy.uix.recycleview import RecycleView Builder.load_string(''' <RV>: viewclass: 'Label' RecycleBoxLayout: default_size: None, dp(56) default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical' ''') class RV(RecycleView): def __init__(self, **kwargs): super(RV, self).__init__(**kwargs) self.data = [{'text': str(x)} for x in range(100)] class TestApp(App): def build(self): return RV() if __name__ == '__main__': TestApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea9a45f.1c69fb81.8412f.3078SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
You might find this example of a RecycleView more helpful.
Here are a few key concepts. The RecycleView only has the number of widgets that are visible on the screen. The widgets are recycled to create the illusion of a long list. Create a viewclass that represents the object you want on the list. The values for the attributes of the list come from a list of dictionaries. You will create a view class that combines the image, artist and song data.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
kv =
"""
<ThreeLabel>:
Label:
text: root.year
Label:
text: root.club
Label:
text: root.apps
TestBox:
orientation: 'vertical'
ThreeLabel:
year: 'Year'
club: 'Club'
apps: 'Apps'
size_hint_y: None
height: 48
RecycleView:
viewclass: 'ThreeLabel'
data: root.rv_data_list
scroll_type: ['bars','content']
bar_width: dp(20)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
"""
class ThreeLabel(BoxLayout):
year = StringProperty()
club = StringProperty()
apps = StringProperty()
class TestBox(BoxLayout):
rv_data_list = [{'year': str(1999 + n), 'club': str(n + 100), 'apps':str(n + 200) } for n in range(100)]
class RVTestApp(App):
def build(self):
return Builder.load_string(kv)
RVTestApp().run()
From: Raja Ramesh
Sent: Wednesday, April 29, 2020 10:16 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
yes Elliot, my next steps were to display the folders on app which contain mp3 files in gridlayout with album art of the songs. Now, i am able to drag and drop the song and by clicking the play button song is playing.
Now i am trying to understand below recycleview code. but it is not displaying anything after running the code. i got this example from https://kivy.org/doc/stable/api-kivy.uix.recycleview.html could you please let me know what was wrong. currently my aim is to display the songs which i drag and drop on to the app and play the song on clicking the song from playlist.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgoTdW7zaw38UGF%3DcXo%2B6mO3E8E-L1_fT2TmcjVn8n0Ag%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ea9f61b.1c69fb81.18a85.1076SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
There are a few things going on here.
You could start simple with:
<SongFile>:
Label:
text: root.song_file
class SongFiile(BoxLayout):
song_file = StringProperty()
and then additional attributes as you get things working. Take a close look at the view class in the example I sent previously (ThreeLabel).
[{‘song_file’: filename}, {‘song_file’: filename},…]
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViiPs%3DLt-NLCP3u-Mk5cv%3DPxOrSW_1cb%3DE5LFKE2SDATg%40mail.gmail.com.
from kivy.app import App
from kivy,lang import Builder
from kivy.uix.boxlayout import Boxlayout
from kivy.core.window import Window
from kivy.properties import ListProperty, StringProperty
kv = '''
<SongFile>:
Label:
text: root.song_file
playlist:
orientation: 'vertical'
SongFile:
song_file: 'SongList'
size_hint_y: None
height: 48
RecycleView:
id: rv_data_list
viewclass: 'SongFile'
scroll_type: ['bars', 'content']
bar_width: dp(15)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
'''
class SongFile(BoxLayout):
song_file = StringProperty()
class playlist(BoxLayout):
file_list = ListProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
Window.bind(on_dropfile = self._on_file_drop)
def _on_file_drop(self, window, file_path):
class RVPlayList(App):
def build(self):
return Builder.load_string(kv)
RVPlayList().run()
for filename in self.file_list:
self.ids.rv_data_list.data = [{ 'song_file': str(filename)}] # it gives last file
In this code above you are writing one data element per iteration, one on top of the other.
The code below is a list comprehension. The it is creating a list, appending more data for each iteration.
Do a search for list comprehension to learn more.
self.ids.rv_data_list.data = [{ 'song_file': str(filename)} for filename in self.file_list] # it gives all file
It would be more natural just to add to append to the list:
def _on_file_drop(self, window, file_path):
d = {'song_file': file_path.decode()}
self.rv_file_list.append(d)
From: Raja Ramesh
Sent: Thursday, April 30, 2020 10:19 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
hi Elliot,
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vg3%3DMOOb_oyL5%3DT9PmTCAJ-dL2a_CENq7eE_9TSHT6-Ow%40mail.gmail.com.
kv = '''
<SongFile>:
Label:
text: root.song_file
playlist:
orientation: 'vertical'
BoxLayout:
size_hint: .3,.2
pos_hint: {'center_x': .8, 'center_y': .8}
SongFile:
song_file: 'SongList'
size_hint_y: None
height: 48
BoxLayout:
size_hint: .3,.2
pos_hint: {'center_x': .8, 'center_y':.8}
RecycleView:
id: rv_data_list
viewclass: 'SongFile'
scroll_type: ['bars', 'content']
bar_width: dp(15)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
'''
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5eab28ee.1c69fb81.9d5aa.192bSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
To change the alignment of the song names. Make the change to the Label in SongFile.
See: https://kivy.org/doc/stable/api-kivy.uix.label.html?highlight=label#text-alignment-and-wrapping
To create ‘gaps’ on the top and bottom of the RecycleView, add padding to the enclosing BoxLayout.
Padding can be expressed as 4 values. Look in the docs for BoxLayout, padding. Add padding to the top and bottom.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vg_R7RGAWOtMQ6TvBDOFPF-%2Bvbgj2%3D%2BGZmmcJuQnNef-g%40mail.gmail.com.
<SongFile>:
orientation: 'vertical'
Label:
text: root.song_file
pos_hint: {'center_x':.55, 'center_y':.4}
drag:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
pos_hint:{'center_x': .8, 'center_y':.7}
padding: [0,200]
SongFile:
song_file: 'SongList'
RecycleView:
orientation: 'vertical'
canvas:
Color:
rgba: (0.524,0.543,.854,.53)
Rectangle:
size: self.size
pos: self.pos
size_hint: .3,.9
pos_hint: {'center_x':.55, 'center_y':.4}
id: rv_data_list
viewclass: 'SongFile'
#data: root.rv_data_list
scroll_type: ['bars','content']
bar_width: dp(15)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(36)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5eac21be.1c69fb81.eb3b1.0ff8SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
when i increase padding value , recycleview is decreasing. is there any way to make the recycleview not to decrease.
You could give the enclosing boxlayout a size. It looks like you are putting this layout together based on a FloatLayout. I would encourage you to use a set of nested BoxLayouts, and not use FloatLayout. This will scale with Window size and require less manual positioning of the widgets.
Also the scroll bar is not visible or highlighted until i place cursor on scrollbar. so, i add color to view. Is there a way to make the scrollbar highlighted without placing cursor?
When you look at the documentation for RecycleView, you will see it is derived from ScrollView.

Inside ScrollView you will find the attributes: bar_color and bar_inactive_color. Use those attributes to change the color of the scrollbar.
To change the text alignment in the long list:
<SongFile>:
orientation: 'vertical'
Label:
text: root.song_file
text_size: self.size
haligh: 'left'
valign: 'center'
padding: 5, 0
From: Raja Ramesh
Sent: Friday, May 1, 2020 2:20 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
hi elliot,
with below code i am able to manage recycleview . but when i increase padding value , recycleview is decreasing. is there any way to make the recycleview not to decrease. Also the scroll bar is not visible or highlighted until i place cursor on scrollbar. so, i add color to view. Is there a way to make the scrollbar highlighted without placing cursor? i like to view the slider dial / knob to appear when i place cursor on the app. could you please help how to do.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgW0%3Dqp8kUy2NnTNPqGbgGFB95M2U8MLyyabnM%3D%3D%3DJg%3Dg%40mail.gmail.com.

from kivy.app import App
from kivy.core.window import Window
from kivy.core.audio import SoundLoader
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.slider import Slider
from kivy.properties import ListProperty, StringProperty
from mutagen import File
import os
from glob import glob
kv = '''
<SongFile>:
orientation: 'vertical'
Label:
text: root.song_file
pos_hint: {'center_x':.55, 'center_y':.4}
text_size: self.size
haligh: 'left'
valign: 'center'
padding: 5, 0
<drag>:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
#Image:
# id: album_image
# source: root.album_art
# allow_strech: True
# size_hint: 100,10
# pos_hint: {'center_x':.6, 'center_y': .5}
SongFile:
song_file: 'SongList'
RecycleView:
orientation: 'vertical'
pos_hint: {'center_x':.55, 'center_y':.4}
id: rv_data_list
viewclass: 'SongFile'
#data: root.rv_data_list
scroll_type: ['bars','content']
bar_color: 1,0,0,1
bar_inactive_color: 1,0,0,0.5
bar_width: dp(15)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(36)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
BoxLayout:
size_hint_y: None
Label:
#text: '00:00'
text: root.song_time
size_hint: .3,.2
pos_hint: {'center_x':.1, 'center_y':.4}
TouchSlider:
id:pos_slider
value_track: True
value_track_color: (1,0,0,1)
size_hint: 2.8, 0.2
pos_hint: {'center_x':.01, 'center_y':.4}
on_press: root.go_to_pos(self.value)
Label:
#text:'00:00'
text: root.song_time_end
size_hint: .3, .2
pos_hint: {'center_x':.1,'center_y': .4}
BoxLayout:
#orientation:'vertical'
size_hint_y: None
#padding: [150,105]
height: 40
#cols:2
Button:
text: 'prev'
on_press: root.previous()
Button:
text: 'pause'
on_press: root.pause()
Button:
text: 'play'
on_press: root.play()
Button:
text: 'next'
on_press: root.next()
Button:
text: 'stop'
on_press: root.stop()
BoxLayout:
orientation: 'vertical'
Label:
text: 'Audio File Player'
font_size: 30
size_hint: .3,.2
pos_hint: {'center_x':.5, 'center_y':.9}
drag:
padding:[130,70]
'''
class SongFile(BoxLayout):
song_file = StringProperty()
class TouchSlider(Slider):
def __init__(self, **kwargs):
self.register_event_type('on_release')
self.register_event_type('on_press')
self.register_event_type('on_move')
super().__init__(**kwargs)
def on_press(self):
pass
def on_release(self):
pass
def on_move(self):
pass
def on_touch_down(self, touch):
super().on_touch_down(touch)
if self.collide_point(*touch.pos) and self.disabled is False:
self.dispatch('on_press')
return True
class drag(BoxLayout):
#pass
songs = ListProperty() # use this when using drag and drop method
player_state = StringProperty('ready')
song_time_end = StringProperty('00:00')
song_time = StringProperty('00:00')
album_art = StringProperty(r'music_logo.png') # image_NEW.jpg # Added a property ***Put default Image Here***.
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.song = None
self.song_index = 0
self.stop_pressed = False
self.song_position = 0
self.paused = False
self.player_state = 'ready'
Window.bind(on_dropfile=self._on_file_drop) def _on_file_drop(self, window, file_path):
self.songs.append(file_path.decode('utf-8'))
print(self.songs)
self.ids.rv_data_list.data = [{'song_file': str(os.path.basename(filename))} for filename in self.songs]
def play(self):
if self.player_state == 'pause':
self.song.play()
self.song.seek(self.song_position)
print('seek position is:- %s' % (self.song.seek(self.song_position)))
self.player_state = 'ready'
return
if self.song:
if self.song.state == 'play':
self.player_state = 'stop' # pressing play while playing... is hitting stop then play
self.song.stop()
self.song = SoundLoader.load(self.songs[self.song_index])
self.song.bind(on_stop=self.song_end) # when the on_stop event fires, execute song_end
if self.song:
#self.song.volume = 0.2
self.song.play()
self.song_name = self.songs[self.song_index]
self.song_time_end = self.pos_to_min_sec(self.song.length)
self.schedule = Clock.schedule_interval(self._play_status, 0.1)
self.image() # calling image method to update image
self.ids.album_image.reload() # this will change the image of song when song changes. if this is not include the filename stays the same with first song.
def image(self):
self.destination = r'image_NEW.jpg' # for image saving
print(f'current song name:- {os.path.basename(self.songs[self.song_index])}')
self.album = File(self.songs[self.song_index])
self.cover = self.album['APIC:'].data
with open(self.destination, 'wb') as img:
img.write(self.cover)
self.album_art = r'image_NEW.jpg'
def next(self):
# related to next
def previous(self):
#related to previous
def stop(self):
def pause(self):
class dragdropmusic(App):
def build(self):
return Builder.load_string(kv)
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ead7c50.1c69fb81.49f7.2d6cSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Do a sketch of where you want the different elements on the screen.
From: Raja Ramesh
Sent: Friday, May 8, 2020 8:48 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
Now i am trying to implement music player using BoxLayout as per your suggestion in previous post. with below code i am able to implement button and slider code. But i am not able to implement the code to display image of album art and songslist side - by- side. for this we need to use orientation :'horizontal' in BoxLayout. could you please suggest how to use.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgF1JY%2BPY%2BX0UGcPtbb%2B61oPNBx2ME8rEi%3DbJpzR%2B6wfQ%40mail.gmail.com.

In the image below, Have drawn blue boxes to show the major layout elements.
Overall there is a vertical BoxLayout.
In the large panel in the middle there is a horizontal BoxLayout. The trick is to create a blank or placeholder for the space on the left. You could use a label with no text as a placeholder. Something like:
BoxLayout: # This is for the 3 items in the big panel
Label: # used a placeholder
Image:
Source: ‘album_art.png’
Playlist:

From: Raja Ramesh
Sent: Friday, May 8, 2020 11:16 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
i would like to view the app as below,

Thanks,
Raja
On Fri, May 8, 2020 at 9:50 PM Elliot Garbus <elli...@cox.net> wrote:
Do a sketch of where you want the different elements on the screen.
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VhDrC4W7BXXbDe%2BSoYRL8gM2Dvvhtb_qx%2B0YL_mAAYMqA%40mail.gmail.com.
Combine the SongFile and RecycleView together in a Vertical BoxLayout, under the Horizontal BoxLayout
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViHL3O2fkoSZNuK7-22Me34dh%2B7DFty9Pkm4tMs7BVphA%40mail.gmail.com.
def image(self):
# Below code is for mp3 image
self.destination = r'c:\my files\image_NEW.jpg' # for image saving
print(f'current song has album art:- {os.path.basename(self.songs[self.song_index])}')
self.album = File(self.songs[self.song_index])
self.cover = self.album['APIC:'].data
if self.cover:
with open(self.destination, 'wb') as img:
img.write(self.cover)
self.album_art = r'c:\my files\image_NEW.jpg' # this will update the image of song when song changes and replace in required place to display image on app.
else:
print(f'current song has no album art:- {os.path.basename(self.songs[self.song_index])}')
self.album = File(r'C:\my files\music_logo.png')
self.cover = self.album['APIC:'].data
with open(self.destination, 'wb') as img:
img.write(self.cover)
self.album_art = r'c:\my files\image_NEW.jpg'
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5eb6ef5a.1c69fb81.fae9a.9c6aSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
In the else clause, can you just set the Image to r'C:\my files\music_logo.png?
Are you executing the else clause?
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VjTJiS8arvwVw4orHSZFHFvRAYwWP%2BhFcDD%2BeGuGDQoug%40mail.gmail.com.
Perhaps I don’t understand some of the other logic in you app, It seems you could do something like:
else:
print(f'current song has no album art:-{os.path.basename(self.songs[self.song_index])}')
with open(self.destination, 'wb') as img:
img.write(r'C:\my files\music_logo.png')
self.album_art = r'c:\my files\image_NEW.png'
OR
else:
print(f'current song has no album art:-{os.path.basename(self.songs[self.song_index])}')
self.album_art = r'C:\my files\music_logo.png'
Also note that you were switching file extensions between png and jpg – this won’t work.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vgy5yn%3DCtaCL3VVs75X2PxvbrtvvMySgN65DuXBdWpEGA%40mail.gmail.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5eb85761.1c69fb81.81739.0afdSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
To make the right click menu will take a few steps.
Use Config.set to turn off multi-touch:
Config.set('input', 'mouse', 'mouse,disable_multitouch')
You will need to create an on_touch_down() and on_touch_up() method for each widget in the song list that uses the right click.
The context menu will be a a set of labels (or buttons) in a FloatLayout.
From: Raja Ramesh
Sent: Monday, May 11, 2020 9:14 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
i have modified the logic and the app is changing the image as per the song. But for few songs which i recorded from youtube, it gives an error saying 'mutagen.id3._util.ID3NoHeaderError: 'bit song.mp3' doesn't start with an ID3 tag' . i am googling for this .Also how to make as below by right clicking an MP3 file.
Thanks,
Raja
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vh0Y8-dgxFrOEaSUK1i70WgR2gQ%3D3NkJd49zubw9aKUzw%40mail.gmail.com.
Here is an example of a custom widget I created that uses a right click.
Look at the on_touch_down() method to see how the right click is captured. You can run this file stand alone to create some experiments.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, StringProperty
from kivy.lang import Builder
Builder.load_string('''
#-------------------------------
# Knob class
# Properties are: text, values, value
#
#-------------------------------
#: set black [0, 0, 0, 1]
#: set white [1, 1, 1, 1]
<CircleKnob>
orientation: 'vertical'
opacity: .25 if root.disabled else 1
Label:
font_size: '25sp'
color: root.text_color
text: root.values[root.value]
canvas:
Color:
rgba: root.arc_foreground
Line:
circle: self.center_x, self.center_y, self.height/2 *.9, -140, 140
cap: 'square'
width: dp(3)
canvas.after:
Color:
rgba: root.arc_background
Line:
circle:
(
self.center_x, self.center_y,
self.height/2 *.9,
-140, -140 + root.value * 280 / ( len(root.values) - 1 )
)
cap: 'square'
width: dp(3)
Label:
font_size: '20sp'
text: root.text
size: self.texture_size
size_hint_y: None
color: root.text_color
#-------------------------------
''')
class CircleKnob(BoxLayout):
text = StringProperty()
arc_background = ListProperty([1, 1, 1, 1])
arc_foreground = ListProperty([0, 0, 0, 1])
text_color = ListProperty([0, 0, 0, 1])
values = ListProperty([str(i) for i in range(128)])
value = NumericProperty(0)
mouse_set_value = NumericProperty(0) # set when a mouse moves, triggers sending a midi msg
right_click_value = NumericProperty(0)
_scroll_direction = {'scrollup': 1, 'scrolldown': -1}
def on_touch_down(self, touch):
if self.collide_point(*touch.pos) and self.disabled is False:
if touch.device == 'mouse' and touch.button == 'right':
self.value = self.right_click_value
else:
touch.grab(self)
return True
return False
def on_touch_move(self, touch):
if touch.grab_current is self and touch.dy and self.disabled is False:
# sorted(min, val, max)[1] works to clamp val to floor or ceiling
self.value = (sorted((0, self.value + int(touch.dy), len(self.values) - 1))[1])
self.mouse_set_value = self.value
return True
return False
def on_touch_up(self, touch):
if touch.is_mouse_scrolling and touch.grab_current is self and self.disabled is False:
# sorted(min, val, max)[1] works to clamp val to floor or ceiling
self.value = (sorted((0, self.value + self._scroll_direction.get(touch.button, 0),
len(self.values) - 1))[1])
self.mouse_set_value = self.value
return True
elif touch.grab_current is self:
touch.ungrab(self)
return True
return False
@property
def knob_value(self):
return self.value
@knob_value.setter
def knob_value(self, v):
self.value = v
if __name__ == '__main__':
kv_test = '''
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgb: .7, .7, .7
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: .1
Button:
text: "CircleKnob Test"
GridLayout:
rows: 2
cols: 5
CircleKnob:
text: "Pulse Width"
values: [str(x) for x in range(101)]
CircleKnob:
values: [str(x) for x in range(-24, 25)]
value: 24
text: 'Pitch'
CircleKnob:
values: ['L'+str(-x) for x in range(-50, 0)] + ['CTR'] + ['R'+ str(x) for x in range(1, 51)]
value: 50
text: 'Pan'
right_click_value: 50
CircleKnob:
text: "Rate"
disabled: True
CircleKnob:
text: "One"
values: [str(x) for x in range(101)]
CircleKnob:
values: [str(x) for x in range(-24, 25)]
value: 3
text: 'Pitch Bend'
CircleKnob:
values: ['L'+str(-x) for x in range(-50, 0)] + ['CTR'] + ['R'+ str(x) for x in range(1, 51)]
value: 1
text: 'Pan'
CircleKnob:
text: "Default"
CircleKnob:
text: "Pulse Width"
values: [str(x) for x in range(101)]
CircleKnob:
values: [str(x) for x in range(-24, 25)]
value: 3
text: 'Pitch'
right_click_value: 24
'''
from kivy.config import Config
from kivy.core.window import Window
Config.set('input', 'mouse', 'mouse,disable_multitouch')
class CircleKnobApp(App):
def build(self):
Window.size = 700, 300
return Builder.load_string(kv_test)
CircleKnobApp().run()
From: Raja Ramesh
Sent: Monday, May 11, 2020 9:52 AM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] play audio from stop position in kivy
Hi Elliot,
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViHk%2BhcM6VQQ63cepmJGhCUiTOx3JZSotiKto9MywUCmg%40mail.gmail.com.
Do you want to add items to a context menu in Windows Explorer?
I had thought the context menu was for in your own app.
I don’t know how to add context menus, but doing a search there are a number of examples around.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VjFL6JaLm3kFJuKTi0NBEAF-TEJ50zCHkst_yGq6wgfQw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VgDUZz6skxVGfZrT3-qYhWeX2Deo4rrYV-cfb%3DnMYJwEQ%40mail.gmail.com.
Have you set:
> self.song.volume = self.volume
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-ViV6kY4CBp%2BMZx9ipDy7CdFehM-8%2B51YCh7OY0Z%3DtQNDw%40mail.gmail.com.
How is your playlist constructed? What is the widget?
One simple idea, assuming you have a compound widget in a BoxLayout, you could add a color as the background, using canvas, and change the color if the widget is selected.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VhDxxYVTDJoJKfQEJccn7CtkWtQvncBhB_Mym%2BM-%2BZoEQ%40mail.gmail.com.
Here is an example of highlighting a song. I added a TextInput to the top of the window. If the text typed matches a song in the list, that song is highlighted with the highlight color. Note
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty
kv = """
<ThreeLabel>:
canvas:
Color:
rgba: root.highlight_color
Rectangle:
size: self.size
pos: self.pos
padding: 20,0
Label:
text: root.song
Label:
text: root.album
Label:
text: root.artist
text_size: self.size
haligh: 'left'
valign: 'center'
padding: 5, 0
TestBox:
orientation: 'vertical'
TextInput:
size_hint_y: None
height: 48
hint_text: 'Enter Song Name'
multiline: False
on_text: root.highlight_song(self.text)
Label:
text: 'Song List'
size_hint_y: .1
RecycleView:
id:rv
viewclass: 'ThreeLabel'
data: root.rv_data_list
scroll_type: ['bars','content']
bar_inactive_color: 1,1,1,1
bar_width: dp(20)
do_scroll_x: False
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
"""
class ThreeLabel(BoxLayout):
song = StringProperty()
album = StringProperty()
artist = StringProperty()
highlight_color = ListProperty()
class TestBox(BoxLayout):
rv_data_list = [{'song': f'song_{n}',
'album': f'album_{n}',
'artist': f'artist_{n}',
'highlight_color': [0, 0, 0, 1]} for n in range(20)]
def highlight_song(self, song):
for track in self.rv_data_list:
track['highlight_color'] = (.8,.8,.8,1) if song == track['song'] else (0, 0, 0, 1)
self.ids.rv.refresh_from_data()
class RVTestApp(App):
def build(self):
return Builder.load_string(kv)
RVTestApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vh7H5ymoO5MXbxq1FKQqs%2B_y6RBbTWrDsQ2ZORX86gp%2Bw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ebebdb2.1c69fb81.1568e.960aSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
The delete is similar to the highlight.
Find the item to delete (perhaps add a delete button to the viewclass). Remove the item from the rv_data_list, and then refresh from data. Give it a try.
What do you want to do with the drag and drop? What do you want to drag from and to, and what is the action?
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vg5QyyZdG-iZ%2BuTx10YRiFUQJBqiB_zcSx3sxA0JT15Jg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ec03a00.1c69fb81.9bae2.dbe9SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
My intention is to move the selected song up and down in the Recycleview. I’m not sure what you mean here, but to change where a song appears in the RecycleView, change the order of the data list.
To remove an item from the recycleview, remove it’s entry from the recycleview data list.
Building on the example from highlighting a song, I’ve added a delete button to each data item. I also added an index to each item in the list. This make it easy to delete the song.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty, NumericProperty
kv = """
<ThreeLabel>:
canvas:
Color:
rgba: root.highlight_color
Rectangle:
size: self.size
pos: self.pos
padding: 20,0
Label:
text: root.song
Label:
text: root.album
Label:
text: root.artist
Button:
size_hint_x: None
width: 80
text: 'Delete'
on_release: root.delete_song()
class ThreeLabel(BoxLayout):
index = NumericProperty()
def delete_song(self):
app = App.get_running_app()
del app.root.ids.rv.data[self.index]
class TestBox(BoxLayout):
rv_data_list = [{'song': f'song_{n}',
'album': f'album_{n}',
'artist': f'artist_{n}'
,
'index': n,
'highlight_color': [0, 0, 0, 1]} for n in range(20)]
def highlight_song(self, song):
for track in self.rv_data_list:
track['highlight_color'] = (.8,.8,.8,1) if song == track['song'] else (0, 0, 0, 1)
self.ids.rv.refresh_from_data()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-VjrghXZs1FGJN4k0k2oPs22oOQd4QvjPNqGGuPT8XnMeg%40mail.gmail.com.
Oops.. The data list indexes need to be updated after a delete.
def delete_song(self):
app = App.get_running_app()
rv = app.root.ids.rv
del rv.data[self.index]
for i, _ in enumerate(rv.data):
rv.data[i]['index'] = i
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ecaa989.1c69fb81.17767.cde6SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5ecaac3c.1c69fb81.3f70d.9fbdSMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Interesting problem. I have not done something like this before. Perhaps some one else has an idea. Start a new thread on this one.
There are a set of calls for selecting a node in the RecycleView. You will also need to decide when is the RecycleView selected vs not selected.
It may a while before I come up with anything. Start with a simple example – and build from there.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CABDb-Vguxv2gVMuhJBVfOLmiB4vsCL3UN2X4Q-6PqUBMpr41jw%40mail.gmail.com.