【问题标题】:Binding slider to adapt to audio position without causing performance degradation绑定滑块以适应音频位置而不会导致性能下降
【发布时间】:2026-02-06 03:10:02
【问题描述】:

我有一个使用 python & kivy 制作的 mp3 播放器应用,我想创建一个滑块,使其值适应歌曲位置。

我已经有了一些解决方案,但所有解决方案的问题是它们使音频播放变得令人不快和故障。

目前我使用 Clock 每秒运行一次功能,但正如我之前提到的,它会使音频非常滞后且无法收听。

我的代码:

import os
os.environ["KIVY_AUDIO"] = "ffpyplayer"
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.app import App


class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.path = "C:/Users/Family/Downloads/10_poker_face.mp3"
        self.song = SoundLoader.load(self.path)
        self.kv = Builder.load_string('''
#:kivy 2.0.0
#:import Clock kivy.clock.Clock
BoxLayout:
    orientation: "vertical"
    Label:
        text: app.path
        font_size: 32
    Slider:
        id: song_slider
        min: 0
        max: app.song.length
        on_value: app.song.seek(self.value)
    Button:
        text: "Play"
        font_size: 32
        on_release:
            Clock.schedule_interval(app.update_slider, 1)
            app.song.play()
''')

    def build(self):
        return self.kv

    def update_slider(self, dt):
        self.kv.ids.song_slider.value = self.song.get_pos()


if __name__ == "__main__":
    MainApp().run()

我什至尝试了线程替代方案,但这比时钟方法更糟糕:

import os
os.environ["KIVY_AUDIO"] = "ffpyplayer"
from threading import Thread
from time import time
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.app import App


class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.path = "C:/Users/Family/Downloads/10_poker_face.mp3"
        self.song = SoundLoader.load(self.path)
        self.start_time = None
        self.kv = Builder.load_string('''
#:kivy 2.0.0
BoxLayout:
    orientation: "vertical"
    Label:
        text: app.path
        font_size: 32
    Slider:
        id: song_slider
        min: 0
        max: app.song.length
        on_value: app.song.seek(self.value)
    Button:
        text: "Play"
        font_size: 32
        on_release: app.start_song()
''')

    def build(self):
        return self.kv

    def start_song(self):
        self.start_time = time()
        Thread(target=self.update_slider, daemon=True).start()
        self.song.play()

    def update_slider(self):
        while True:
            now = time()
            if now - self.start_time >= 1:
                self.start_time = now
                self.kv.ids.song_slider.value = self.song.get_pos()


if __name__ == "__main__":
    MainApp().run()

如何绑定滑块以适应歌曲的音频位置而不引起性能问题?

【问题讨论】:

    标签: python python-3.x kivy kivy-language


    【解决方案1】:

    我可以提供这样的解决方案,它独立于 KIVY_AUDIO 参数工作。

    import os
    os.environ["KIVY_AUDIO"] = "ffpyplayer"
    from kivy.lang import Builder
    from kivy.core.audio import SoundLoader
    from kivy.clock import Clock
    from kivy.app import App
    
    KV = '''
    BoxLayout:
        padding: 10
        orientation: 'vertical'
        
        Label:
            text: app.path
            halign: 'center'
            font_size: sp(32)
            text_size: self.width, None
            size_hint: 1, None
            height: self.texture_size[1]
    
        Slider:
            id: song_slider
            min: 0
            max: 100
            
        Button:
            id: btn
            text: 'Play'
            font_size: sp(32)
            on_release: app.start_song()
    '''
    
    
    class MainApp(App):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.path = 'music.mp3'
    
            self.song = SoundLoader.load(self.path)
            self.clock_event = None
            self.kv = Builder.load_string(KV)
    
        def build(self):
            return self.kv
    
        def start_song(self):
            if self.song.state == 'stop':
                self.song.play()
                self.clock_event = Clock.schedule_interval(self.update_slider, self.song.length / 60)
                self.kv.ids.btn.text = 'Stop'
            else:
                self.clock_event.cancel()
                self.song.stop()
                self.kv.ids.song_slider.value = 0
                self.kv.ids.btn.text = 'Play'
    
        def update_slider(self, *args):
            if self.kv.ids.song_slider.value < 100:
                self.kv.ids.song_slider.value += 1
    
    
    if __name__ == '__main__':
        MainApp().run()
    

    【讨论】:

      最近更新 更多