问题描述
def add_song():
song = filedialog.askopenfilename(initialdir='C:\\Users\\Soham\\Music',title="Choose a
song!",filetypes=(("mp3 Files","*.mp3"),))
song_name = song.split("/")[-1].split(".")[0]
song_list.insert(END,song_name)
play_button = Button(controls_frame,image=play_button_img,borderwidth=0,command = play)
play_button.grid(row=0,column=2,padx=5)
def play():
song = song_list.get(ACTIVE)
pygame.mixer.music.load(song)
pygame.mixer.music.play(loops=0)
但是这里 play() 中的 dong 变量实际上只是歌曲的名称,因为它已经在 add_song() 中分开了。而且 pygame 需要整个路径,因为歌曲与 python 文件不在同一目录中。所以pygame无法打开和播放歌曲导致错误-
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Soham\AppData\Local\Programs\Python\python39\lib\tkinter\__init__.py",line
1885,in __call__
return self.func(*args)
File "c:\Users\Soham\Desktop\HM MP.py",line 26,in play
pygame.mixer.music.load(song)
pygame.error: Couldn't open 'Avicii - The Nights'
那么我能做些什么呢,有没有另一种方法可以让我分开显示歌曲名称的路径,从而不会为 pygame
播放音乐造成任何问题??
另外,我使用的是 Windows 10 Pro、高端机器和 Python 3。
解决方法
您可以创建具有 dict
{'song name': 'file path'}
,
由于您将歌曲插入列表框并从那里播放,您可以做的是,制作一个索引字典,索引从 0 开始作为键,值作为歌曲名称和路径列表,所以它类似于像song_dict = {idx:[song_name,song_path]}
。因此,每个 idx 都将是您从列表框中选择的。我用这个做了一个例子,看看:
from tkinter import *
from tkinter import filedialog
import pygame
root = Tk()
pygame.mixer.init()
song_dict = {} # Empty dict to assign values to it
count = 0 # An idx number to it increase later
def add_song():
global count
song_path = filedialog.askopenfilename(initialdir='C://Users//Soham//Music',title="Choose a song!",filetypes=(("mp3 Files","*.mp3"),))
song_name = song_path.split("/")[-1].split(".")[0]
song_dict[count] = [song_name,song_path] # Create the desired dictionary
song_list.insert(END,song_name) # Insert just the song_name to the Listbox
count += 1 # Increase the idx number
def play_song(*args):
idx = song_list.curselection()[0] # Get the index of the selected item
song = song_dict[idx][1] # Get the corresponding song from the dictionary
pygame.mixer.music.load(song) # Load the song
pygame.mixer.music.play(loops=0) # Play the song
song_list = Listbox(root,width=50)
song_list.pack(pady=10)
choose = Button(root,text='Choose song',command=add_song)
choose.pack(pady=10)
song_list.bind('<Double-Button-1>',play_song) # Just double click the desired song to play
root.mainloop()
只需双击您要播放的歌曲。您也可以使用按钮代替 bind()
,就像您在代码中所做的那样。
song_dict
的结构示例如下:
{0: ['Shawn Mendes - Perfectly Wrong','C:/PyProjects/sONGS/Shawn Mendes - Perfectly Wrong.mp3'],1: ['Lil Nas X - Old Town Road (feat','C:/PyProjects/sONGS/Lil Nas X - Old Town Road (feat. Billy Ray Cyrus) - Remix.mp3'],2: ['NF - Time - Edit','C:/PyProjects/sONGS/NF - Time - Edit.mp3']}
虽然我也建议制作一个按钮来询问目录并获取该目录中的所有 mp3 文件并填充列表框。
如果你想使用 filedialog.askopenfilenames
那么你可以编辑函数如下:
import os
def add_song():
songs_path = filedialog.askopenfilenames(initialdir='C://Users//Soham//Music',title="Choose a song!")
for count,song in enumerate(songs_path):
song_name = os.path.basename(song)
song_dict[count] = [song_name,song] # Create the desired dictionary
song_list.insert(END,song_name) # Insert just the song_name to the Listbox
在这种情况下,您不需要预定义的 count
变量,因为我们是从 for
循环中创建的。
编辑:
与其使用 split
,不如使用 os.path
,这样您就可以从路径中获取基本名称,例如:
import os
song_name = os.path.basename(song_path) # If its tuple then loop through and follow