Kivy:使用 kivy.clock 为计时器安排声音

Kivy: scheduling sounds with kivy.clock for a timer

我创建了一个计时器,它从一个随机数倒数到零,然后一旦它达到零,它就会移动到一个新屏幕并再次从一个随机数开始倒数。我希望在计时器到达 3、2、1 时发出声音,然后发出不同的声音 0,但我不确定如何实现它。

我尝试通过 SoundLoader 将声音文件加载为 mp3,当按下按钮开始计时时会调用该函数。我目前的理解是,该函数将在调用函数时仅检查一次 self.a =3,2,1 或 0,因此需要 kivy.clock Clock.schedule_interval() 函数来检查每秒 self.a 的值。我试过这个(如下面的代码所示),但是计时器运行了一秒钟然后崩溃,显示错误消息 TypeError: sound() takes 1 positional argument but 2 were given

py文件

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.animation import Animation
from kivy.properties import NumericProperty
from kivy.uix.togglebutton import ToggleButton
from random import randint
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.core.audio import SoundLoader
from kivy.clock import Clock

class MainWindow(Screen):
    pass

class SecondWindow(Screen):
    pass

class ThirdWindow(Screen):
    pass

class FourthWindow(Screen):
    pass

class WindowManager(ScreenManager):
    a = NumericProperty(0)
    b = NumericProperty(0)
    run_t = NumericProperty(30)
    min = NumericProperty(5)
    max = NumericProperty(5)
    sound_done = SoundLoader.load('beep-01a.mp3')
    sound_finishing = SoundLoader.load('beep-07.mp3')

    def sound(self):
        Clock.schedule_interval(self.sound, 1)
        if self.a == 0:
            self.sound_done.play()
        if self.a == 1:
            self.sound_finishing.play()
        if self.a == 2:
            self.sound_finishing.play()
        if self.a == 3:
            self.sound_finishing.play()


    def proceed(self):
            self.reset()
            self.start()
            self.count_up()
            self.sound()
            self.ids.main_window.manager.current = 'low'

    def reset(self):
        self.a = 0
        self.b = 0

    def start(self, *args):
        self.a = randint(self.min, self.max)
        self.anim = Animation(a = 0, duration = self.a)
            if rand == 0:
                self.ids.main_window.manager.current = 'low'
            elif rand == 1:
                self.ids.main_window.manager.current = 'medium'
            elif rand == 2:
                self.ids.main_window.manager.current = 'high'
            self.anim.bind(on_complete = self.start)
        self.anim.start(self)

    def count_up(self):
        self.anim = Animation(b = self.run_t, duration = self.run_t)
        self.anim.bind(on_complete = self.finish_callback)
        self.anim.start(self)

    def finish_callback(self, animation, param):
        Animation.cancel_all(self)


kv = Builder.load_file("final.kv")

class PageScrollerApp(App):
    def build(self):
        return kv

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

kv文件

WindowManager:
    MainWindow:
        id: main_window
    SecondWindow:
        id: second_window
    ThirdWindow:
        id: third_window
    FourthWindow:
        id: fourth_window

<MainWindow>:
    name: "home"

    FloatLayout:
        Button:
            pos_hint: {"x":0.4, "y":0.05}
            size_hint: 0.2, 0.1
            text: "Go!"
            on_release:
                root.manager.proceed()


<SecondWindow>:
    name: 'low'

    FloatLayout:
        Label:
            id: count_down1
            text: str(round(root.manager.a, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.55}
        Label:
            id: count_up1
            text: str(round(root.manager.b, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.3}


<ThirdWindow>:
    name: "medium"

    FloatLayout:
        Label:
            id: count_down2
            text: str(round(root.manager.a, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.55}
        Label:
            id: count_up2
            text: str(round(root.manager.b, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.3}

<FourthWindow>:
    name: "high"

    FloatLayout:
       Label:
            id: count_down3
            text: str(round(root.manager.a, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.55}
        Label:
            id: count_up3
            text: str(round(root.manager.b, 1))
            size_hint: 0.28, 0.1
            pos_hint: {"x": 0.36, "y": 0.3}

编辑

[INFO   ] [Logger      ] Record log in C:\Users\User\.kivy\logs\kivy_19- 
07-12_0.txt
[INFO   ] [Kivy        ] v1.11.0
[INFO   ] [Kivy        ] Installed at "C:\ProgramData\Anaconda3\lib\site- 
packages\kivy\__init__.py"
[INFO   ] [Python      ] v3.7.1 (default, Dec 10 2018, 22:54:23) [MSC 
v.1915 64 bit (AMD64)]
[INFO   ] [Python      ] Interpreter at 
"C:\ProgramData\Anaconda3\python.exe"
[INFO   ] [Factory     ] 184 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2, img_pil, 
img_gif (img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Audio       ] Providers: audio_sdl2 (audio_ffpyplayer ignored)
[WARNING] [Audio       ] Unable to find a loader for <beep-01a.ogg>
[WARNING] [Audio       ] Unable to find a loader for <beep-07.ogg>
[INFO   ] [Window      ] Provider: sdl2
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] GLEW initialization succeeded
[INFO   ] [GL          ] Backend used <glew>
[INFO   ] [GL          ] OpenGL version <b'4.5.13467 Compatibility Profile 
Context 21.19.414.1792'>
[INFO   ] [GL          ] OpenGL vendor <b'ATI Technologies Inc.'>
[INFO   ] [GL          ] OpenGL renderer <b'AMD Radeon R7 Graphics'>
[INFO   ] [GL          ] OpenGL parsed version: 4, 5
[INFO   ] [GL          ] Shading version <b'4.50'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not 
docked
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [Base        ] Start application main loop
[INFO   ] [WindowSDL   ] exiting mainloop and closing.
[INFO   ] [Base        ] Leaving application in progress...

我试图删除与问题无关的任何代码。任何帮助将不胜感激!

当你使用Kivy Clock对象调用回调函数时,你必须提供dtdt表示delta-time)。如果你不这样做,你会遇到,

TypeError: sound() takes 1 positional argument but 2 were given

解决方案

使用lambda函数跳过这个。将 Clock.schedule_interval(self.sound, 1) 替换为 Clock.schedule_interval(lambda dt: self.sound(), 1)

片段

def sound(self):
    int_round_a = int(round(self.a))
    print(f"self.a={self.a}, int_round_a={int_round_a}")
    if int_round_a == 0:
        self.sound_done.play()
    elif int_round_a == 1:
        self.sound_finishing.play()
    elif int_round_a == 2:
        self.sound_finishing.play()
    elif int_round_a == 3:
        self.sound_finishing.play()

def proceed(self):
    self.reset()
    self.start()
    self.count_up()
    Clock.schedule_interval(lambda dt: self.sound(), 1)
    self.ids.main_window.manager.current = 'low'