13 KiB
wxPython:创建一个简单的 MP3 播放器
原文:https://www.blog.pythonlibrary.org/2010/04/20/wxpython-creating-a-simple-mp3-player/
上个月,我开始撰写关于使用 wxPython 创建简单应用程序的系列文章。前两篇文章是关于图像浏览器程序的。虽然我不会放弃这个项目,但我认为现在是我们探索新东西的时候了。在这篇文章中,我们将开始一段旅程,进入玩 MP3 的疯狂世界。我们将创建一个非常简单的界面,可以用来播放、暂停和停止一首歌曲。我们还将学习如何在音轨内搜索并改变音乐的音量。在未来的文章中,我们将添加一个显示音乐信息(如标题,艺术家,流派等),曲目列表,随机功能,等等。我们开始吧!
准备旋转音乐
我们可以使用许多不同的布局,但在这个例子中,我们将使用传统的布局,在顶部有一个水平歌曲轨道滑块小部件,下面有播放器控件,右边有音量控件。如果您熟悉 wxPython 的小部件,那么您可能会认为 ShapedButtons 非常适合这个应用程序。我也这样认为,直到我发现他们依赖于 Python 图像库(PIL)。虽然这没什么大不了的,但是对于一个简单的例子来说,我认为这对本文来说很复杂,所以最终使用了一些通用的按钮。当我们以后改进这个程序时,我们可能会花时间更新按钮,给它们更多的活力。现在,我们的应用程序将如下所示:
它不是世界上最漂亮的音乐播放器,但我们可以稍后修复它。重点是学习如何用 wxPython 创建一个跨平台的应用程序。当我在 Windows XP 机器上运行这个应用程序时,它似乎使用了 ffdshow。当我在 Windows 7 上运行它时,我认为它在后端使用的是 Windows Media Player。据我理解,wx。MediaCtrl 将在 Linux 上包装 GStreamer。不管怎样,我们来看看出处:
#----------------------------------------------------------------------
# player_skeleton2.py
#----------------------------------------------------------------------
import os
import wx
import wx.media
import wx.lib.buttons as buttons
dirName = os.path.dirname(os.path.abspath(__file__))
bitmapDir = os.path.join(dirName, 'bitmaps')
########################################################################
class MediaPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
self.frame = parent
self.currentVolume = 50
self.createMenu()
self.layoutControls()
sp = wx.StandardPaths.Get()
self.currentFolder = sp.GetDocumentsDir()
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.onTimer)
self.timer.Start(100)
#----------------------------------------------------------------------
def layoutControls(self):
"""
Create and layout the widgets
"""
try:
self.mediaPlayer = wx.media.MediaCtrl(self, style=wx.SIMPLE_BORDER)
except NotImplementedError:
self.Destroy()
raise
# create playback slider
self.playbackSlider = wx.Slider(self, size=wx.DefaultSize)
self.Bind(wx.EVT_SLIDER, self.onSeek, self.playbackSlider)
self.volumeCtrl = wx.Slider(self, style=wx.SL_VERTICAL|wx.SL_INVERSE)
self.volumeCtrl.SetRange(0, 100)
self.volumeCtrl.SetValue(self.currentVolume)
self.volumeCtrl.Bind(wx.EVT_SLIDER, self.onSetVolume)
# Create sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
audioSizer = self.buildAudioBar()
# layout widgets
mainSizer.Add(self.playbackSlider, 1, wx.ALL|wx.EXPAND, 5)
hSizer.Add(audioSizer, 0, wx.ALL|wx.CENTER, 5)
hSizer.Add(self.volumeCtrl, 0, wx.ALL, 5)
mainSizer.Add(hSizer)
self.SetSizer(mainSizer)
self.Layout()
#----------------------------------------------------------------------
def buildAudioBar(self):
"""
Builds the audio bar controls
"""
audioBarSizer = wx.BoxSizer(wx.HORIZONTAL)
self.buildBtn({'bitmap':'player_prev.png', 'handler':self.onPrev,
'name':'prev'},
audioBarSizer)
# create play/pause toggle button
img = wx.Bitmap(os.path.join(bitmapDir, "player_play.png"))
self.playPauseBtn = buttons.GenBitmapToggleButton(self, bitmap=img, name="play")
self.playPauseBtn.Enable(False)
img = wx.Bitmap(os.path.join(bitmapDir, "player_pause.png"))
self.playPauseBtn.SetBitmapSelected(img)
self.playPauseBtn.SetInitialSize()
self.playPauseBtn.Bind(wx.EVT_BUTTON, self.onPlay)
audioBarSizer.Add(self.playPauseBtn, 0, wx.LEFT, 3)
btnData = [{'bitmap':'player_stop.png',
'handler':self.onStop, 'name':'stop'},
{'bitmap':'player_next.png',
'handler':self.onNext, 'name':'next'}]
for btn in btnData:
self.buildBtn(btn, audioBarSizer)
return audioBarSizer
#----------------------------------------------------------------------
def buildBtn(self, btnDict, sizer):
""""""
bmp = btnDict['bitmap']
handler = btnDict['handler']
img = wx.Bitmap(os.path.join(bitmapDir, bmp))
btn = buttons.GenBitmapButton(self, bitmap=img, name=btnDict['name'])
btn.SetInitialSize()
btn.Bind(wx.EVT_BUTTON, handler)
sizer.Add(btn, 0, wx.LEFT, 3)
#----------------------------------------------------------------------
def createMenu(self):
"""
Creates a menu
"""
menubar = wx.MenuBar()
fileMenu = wx.Menu()
open_file_menu_item = fileMenu.Append(wx.NewId(), "&Open", "Open a File")
menubar.Append(fileMenu, '&File')
self.frame.SetMenuBar(menubar)
self.frame.Bind(wx.EVT_MENU, self.onBrowse, open_file_menu_item)
#----------------------------------------------------------------------
def loadMusic(self, musicFile):
"""
Load the music into the MediaCtrl or display an error dialog
if the user tries to load an unsupported file type
"""
if not self.mediaPlayer.Load(musicFile):
wx.MessageBox("Unable to load %s: Unsupported format?" % musicFile,
"ERROR",
wx.ICON_ERROR | wx.OK)
else:
self.mediaPlayer.SetInitialSize()
self.GetSizer().Layout()
self.playbackSlider.SetRange(0, self.mediaPlayer.Length())
self.playPauseBtn.Enable(True)
#----------------------------------------------------------------------
def onBrowse(self, event):
"""
Opens file dialog to browse for music
"""
wildcard = "MP3 (*.mp3)|*.mp3|" \
"WAV (*.wav)|*.wav"
dlg = wx.FileDialog(
self, message="Choose a file",
defaultDir=self.currentFolder,
defaultFile="",
wildcard=wildcard,
style=wx.OPEN | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.currentFolder = os.path.dirname(path)
self.loadMusic(path)
dlg.Destroy()
#----------------------------------------------------------------------
def onNext(self, event):
"""
Not implemented!
"""
pass
#----------------------------------------------------------------------
def onPause(self):
"""
Pauses the music
"""
self.mediaPlayer.Pause()
#----------------------------------------------------------------------
def onPlay(self, event):
"""
Plays the music
"""
if not event.GetIsDown():
self.onPause()
return
if not self.mediaPlayer.Play():
wx.MessageBox("Unable to Play media : Unsupported format?",
"ERROR",
wx.ICON_ERROR | wx.OK)
else:
self.mediaPlayer.SetInitialSize()
self.GetSizer().Layout()
self.playbackSlider.SetRange(0, self.mediaPlayer.Length())
event.Skip()
#----------------------------------------------------------------------
def onPrev(self, event):
"""
Not implemented!
"""
pass
#----------------------------------------------------------------------
def onSeek(self, event):
"""
Seeks the media file according to the amount the slider has
been adjusted.
"""
offset = self.playbackSlider.GetValue()
self.mediaPlayer.Seek(offset)
#----------------------------------------------------------------------
def onSetVolume(self, event):
"""
Sets the volume of the music player
"""
self.currentVolume = self.volumeCtrl.GetValue()
print "setting volume to: %s" % int(self.currentVolume)
self.mediaPlayer.SetVolume(self.currentVolume)
#----------------------------------------------------------------------
def onStop(self, event):
"""
Stops the music and resets the play button
"""
self.mediaPlayer.Stop()
self.playPauseBtn.SetToggle(False)
#----------------------------------------------------------------------
def onTimer(self, event):
"""
Keeps the player slider updated
"""
offset = self.mediaPlayer.Tell()
self.playbackSlider.SetValue(offset)
########################################################################
class MediaFrame(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Python Music Player")
panel = MediaPanel(self)
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MediaFrame()
frame.Show()
app.MainLoop()
您可能会注意到,这实际上是这个应用程序的版本#2。在本文底部的可下载源代码中,我包含了使用 Andrea Gavana 的 ShapedButton 控件来控制播放器的原始源代码。我建议你从官方的 wxPython 库获得这个小部件的 SVN 版本,因为在默认安装的 wx 版本中有一个已知的 bug。它还依赖于 wxPython 演示应用程序中包含的位图,所以您也需要将这些位图复制到适当的位置。
无论如何,让我们回顾一下上面代码中的一些内容。首先,我们设置了几个“全局”变量来保存应用程序的目录路径,这样我们就可以找到我们的 bitmaps 文件夹。接下来,我们创建应用程序。因为很多人把他们的音乐存储在他们的文档文件夹中,所以我们使用 wx。StandardPaths 以跨平台的方式找到该位置,并将 currentFolder 属性设置为该位置。当我们浏览要听的音乐时,我们将使用这个属性来存储最后打开的文件夹。我们还设置了一个计时器,用于在播放时更新播放器的音轨滑块。这是从 wxPython 的 MediaCtrl 演示中一字不差地复制过来的。
在 layoutControls 方法中,我们创建必要的小部件,并根据需要将它们添加到适当的 sizers 中。我们还在这里做小部件事件绑定。其余代码处理其他布局任务或生成的事件。它们也是不言自明的。注意, onPrev 和 onNext 方法不做任何事情。这是有意的,因为我们目前没有办法一次加载多首歌曲。我们将在程序的未来版本中添加该功能。
因此,使用该应用程序播放歌曲的基本步骤如下:
- 转到文件并打开
- 导航到一个 MP3 文件并打开它
- 按下播放滑块下方的播放按钮,开始听音乐
这就是全部了。现在你有了一个功能齐全的音乐播放器。是的,它是有限的,但是它应该让您了解 wxPython 有多强大,以及扩展这个示例以满足您的需求有多容易。
