0

我对编程有点陌生。我正在使用 Kivy 框架构建一个简单的应用程序。该应用程序有 15 个按钮。当您按下按钮时,它开始播放旋律。如果此时正在播放任何其他按钮,它应该停止,即不应同时播放多个声音(来自不同实例)。

这就是我所做的——我创建了一个处理停止和播放声音的类方法。按下时,按钮实例将声音对象传递给此类方法。但是,在第一次按下时,由于声音对象还不存在,我的应用程序崩溃了。因此部分的原因try … except AttributeError

class Gumb(Button):
    soundfile = StringProperty(None)
    sound = ObjectProperty(None)
    now_playing_object = None

    def on_soundfile(self, instance, value):
        self.sound = SoundLoader.load(value)

    def on_press(self):
        if self.sound:
            self.__class__.play_sound(self.sound)

    @classmethod
    def play_sound(cls, new_sound_object):
        try:
            if cls.now_playing_object.state != 'stop':
                cls.now_playing_object.stop()
        except AttributeError:
            pass
        cls.now_playing_object = new_sound_object
        cls.now_playing_object.play()

这行得通,但是我不喜欢它,尤其是那try … except部分。必须有更好的方法来做到这一点。有任何想法吗?

谢谢!

更新1:

@toto_tico 为我提供了一些解决方案来规避该try ... except部分。

  1. 使用if而不是异常:

    if cls.now_playing_object != None and cls.now_playing_object.state != 'stop':
        cls.now_playing_object.stop()
    

    虽然,在阅读了关于 python 的 ifs 与异常的效率之后,我不确定我是否应该尝试消除try ... except

  2. 一开始就初始化now_playing_object。为此,我使用了:

    now_playing_object = SoundLoader.load(‘non_existant_file.wav’)
    

    这可行,但感觉有点不可靠(奇怪的是,如果文件名缺少扩展名,Kivy 会抱怨,但如果根本没有文件则不会抱怨)。不过,我想我会用这个。

更新 2:

事实证明,解决方案就在我面前。我只是看不到它。真的没有必要@classmethod

class Gumb(Button):
...
    def play_sound(self):
        if self.__class__.now_playing_object.state is not 'stop':
            self.__class__.now_playing_object.stop()
        self.__class__.now_playing_object = self.sound
        self.__class__.now_playing_object.play()

我已经接受了答案,但真正的答案在评论中。谢谢@toto_tico。

4

2 回答 2

2

你可以检查 if now_playing_objectis None

代替:

try:
    if cls.now_playing_object.state != 'stop':
       cls.now_playing_object.stop()
except AttributeError:
    pass
...

你应该能够做到这一点:

if cls.now_playing_object != None and cls.now_playing_object.state != 'stop':
    cls.now_playing_object.stop()
...

希望能帮助到你。

于 2013-07-24T17:39:53.833 回答
1

取出 if 条件:

如果您不想检查,那么您应该从一开始就初始化变量。我不知道您正在使用的课程,now_playing_object但让我们称之为PlayingObject

代替:

now_playing_object = None

你应该初始化它:

#maybe needs parameters or simple use now_playing_object = ObjectProperty(None)
now_playing_object = Sound() 

然后你可以取出我第一个答案的条件(cls.now_playing_object != None),因为对象总是被初始化。

取出@classmethod

我发现你使用的很有趣@classmethod。我使用 Python 已经有几年了,老实说,这对我来说是全新的。有几个答案取决于你想要做什么。我假设您清楚面向对象编程中实例之间的区别。

如果(1)您只有一个Gumb类的实例,或者(2)您有多个Gumb该类的实例,但它们都控制相同的soundfile,sound和,则您当前的代码可以工作now_playing_object

现在,如果您希望您的 15 个Gumb按钮控制不同soundfile的 ,soundnow_playing_object,那么您不应该使用 @class 方法,也不要使用声明属性的方式(因为您将它们声明为类属性并且您需要它们成为实例)。代码看起来更像这样:

class Gumb(Button):
    # Constructor. 
    def __init__(self,  **kwargs):
        super(Gump, self).__init__(**kwargs)
        #This became attributes of the 
        self.soundfile = StringProperty(None)\
        self.sound = ObjectProperty(None)
        self.now_playing_object = ObjectProperty(None) 

    def on_soundfile(self, instance, value):
        self.sound = SoundLoader.load(value)

    def on_press(self):
        if self.sound:
            self.play_sound()

    def play_sound(self):
        if self.now_playing_object.state != 'stop':
            self.now_playing_object.stop()

        # self.sound was your new_playing_object, since it is part of the instance
        # you don't need to send it as parameter
        self.now_playing_object = self.sound
        self.now_playing_object.play()

这和你想要的更相似吗?

于 2013-07-25T02:12:08.813 回答