我对编程有些新意。我正在使用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
部分。必须有更好的方法来做到这一点。 任何想法?
谢谢!
@toto_tico为我提供了几个绕过try ... except
部分的解决方案。
使用if
代替例外:
if cls.now_playing_object != None and cls.now_playing_object.state != 'stop':
cls.now_playing_object.stop()
虽然在阅读了python的ifs与例外的效率之后,我不确定我是否应该尝试消除try ... except
。
在一开始就初始化now_playing_object
。为此,我使用了:
now_playing_object = SoundLoader.load(‘non_existant_file.wav’)
这样可行,但感觉有点不可靠(奇怪的是,如果文件名错过扩展名,Kivy会抱怨,但如果根本没有文件则不会抱怨)。 然而,我想我会用这个。
事实证明,解决方案就在我面前。我只是看不到它。实际上不需要@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。
答案 0 :(得分:2)
您只需检查now_playing_object
是否为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()
...
希望它有所帮助。
答案 1 :(得分: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中已经有几年了,说实话,这对我来说是全新的。根据您的尝试,有几个答案。我将假设您清楚了解Oriented-Object Programming中class和instance之间的区别。
如果(1)您只有Gumb
类的实例或(2)您有几个Gumb
类的实例但是所有它们控制着相同的soundfile
,sound
和now_playing_object
。
现在,如果您希望15个Gumb
按钮控制不同的soundfile
,sound
和now_playing_object
,那么您不应该使用@class方法,也不应该使用@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()
这与你想要的更相似吗?