我正在用 Python 为我的第一个学校项目创建一个音乐库。我在这种情况下的计划是,当单击“播放”按钮(三角形)时,图像的路径/它的变量会发生变化并将其转换为“暂停”图像(两条平行的垂直线)。我可以想象它与 .set() 有关,但我不确定如何使用它,因为这是我在 python 中的第一周。
完整代码如下:
# GUI #
import tkinter as tk
from tkinter import *
from tkinter import filedialog
# AUDIO #
from pygame import mixer
# DIRECTORY NAVIGATION #
from os import walk
# EXCEPTION HANDLER #
import pygame
# VOLUME CONTROL #
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume, ISimpleAudioVolume
from ctypes import cast, POINTER
# YOU MIGHT NEED TO PIP INSTALL THESE
# IF THOSE DONT WORK TRY
# py -m pip install [library]
# pip install pycaw
# pip install comtypes
# pip install psutil
from PIL import Image, ImageTk
class MP:
def __init__(self, win):
# Create Tkinter window
win.geometry('600x300')
win.title('Jared AIT Music Player')
win.resizable(0, 0)
win.iconbitmap('icon.ico')
# StringVar to change button text later
self.play_restart = tk.StringVar()
self.pause_resume = tk.StringVar()
self.play_restart.set('Play')
self.pause_resume.set('Pause')
# The buttons and their positions
self.loadpngPATH = tk.StringVar()
self.loadpngPATH.set('load.png')
self.load_image = Image.open(self.loadpngPATH)
resized = self.load_image.resize((50,50))
self.login_btn = ImageTk.PhotoImage(resized)
self.background_image = Image.open('background.png')
back_res = self.background_image.resize((600,300))
self.backphoto = ImageTk.PhotoImage(back_res)
back_image = Label(image = self.backphoto)
back_image.image = self.backphoto
back_image.place(x = 300, y = 150, anchor = 'center')
self.play_image = Image.open('play.png')
play_res = self.play_image.resize((50,50))
self.playphoto = ImageTk.PhotoImage(play_res)
self.pause_image = Image.open('pause.png')
pause_res = self.pause_image.resize((50,50))
self.pausephoto = ImageTk.PhotoImage(pause_res)
self.stop_image = Image.open('stop.png')
stop_res = self.stop_image.resize((50,50))
self.stop_photo = ImageTk.PhotoImage(stop_res)
self.forward_image = Image.open('forward.png')
forward_res = self.forward_image.resize((50,50))
self.forward_photo = ImageTk.PhotoImage(forward_res)
self.back_image = Image.open('back.png')
back_res = self.back_image.resize((50,50))
self.back_photo = ImageTk.PhotoImage(back_res)
load_button = Button(win, text='Load', width=55, height = 55, font=("Arial", 10), command=self.load, image = self.login_btn, bg = 'white', borderwidth = 0, highlightthickness=0)
load_button.place(x=50,y=250, anchor='center')
play_button = Button(win, textvariable=self.play_restart, width=55, height = 55, font=("Arial", 10), command=self.play, image = self.playphoto, borderwidth = 0, bg = 'white', highlightthickness=0)
play_button.place(x=150,y=250, anchor='center')
pause_button = Button(win, textvariable=self.pause_resume, width=55, height=55, font=("Arial", 10), command=self.pause, image = pself.ausephoto, bg = 'white', borderwidth = 0, highlightthickness=0)
pause_button.place(x=250,y=250, anchor='center')
stop_button = Button(win,width=55, height=55, font=("Arial", 10), command=self.stop, image = self.stop_photo, borderwidth = 0, highlightthickness=0, bg="white")
stop_button.place(x=350,y=250, anchor='center')
next_button = Button(win ,width=55, height=55, font = ('Arial', 10), command = self.next, image = self.forward_photo, borderwidth = 0, highlightthickness=0, bg="white")
next_button.place(x=550,y=250, anchor='center')
back_button = Button(win ,width=55, height=55, font = ('Arial', 10), command = self.back, image = self.back_photo, borderwidth = 0, highlightthickness=0, bg="white")
back_button.place(x=450,y=250, anchor='center')
#SLIDERS
volume_slider = Scale(win, from_=100, to=0, orient=VERTICAL, command=self.volume, length=125)
volume_slider.grid(row=0, column=1)
self.music_file = False
self.playing_state = False
mainloop()
#IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE
#IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE IMAGE
def volume(self,volume_level):
# THIS INITIALISES THE VOLUME CONTROL #
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(
IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
# THIS SETS THE VOLUME #
volume.SetMasterVolumeLevelScalar(int(volume_level)/100, None)
def load(self):
self.music_file = filedialog.askopenfilename(initialdir="/AIT Python 1/Assets", title="Select a song", filetypes=(("wav files", "*.wav"),("all files", "*.*"),("mp3 files", "*.mp3")))
print("Loaded:", self.music_file)
self.play_restart.set('Play')
def play(self):
if self.music_file:
mixer.init()
mixer.music.load(self.music_file)
mixer.music.play()
self.playing_state = False
self.play_restart.set('Restart')
self.pause_resume.set('Pause')
def pause(self):
if not self.playing_state:
mixer.music.pause()
self.playing_state = True
self.pause_resume.set('Resume')
else:
mixer.music.unpause()
self.playing_state = False
self.pause_resume.set('Pause')
def stop(self):
mixer.music.stop()
########################################################################################################
def next(self):
self.file_path = (self.music_file.rsplit("/",1))[0].replace("/","\\")
if "/" in self.music_file:
self.file_name = self.music_file.rsplit("/",1)[1]
else:
self.file_name = self.music_file
self.filenames = next(walk(self.file_path), (None, None, []))[2]
self.file_count = 0
for i in self.filenames:
if i == self.file_name:
break
self.file_count += 1
self.next_file = self.file_count + 1
self.directory_limit = len(self.filenames)
if self.next_file == self.directory_limit:
self.next_file = 0
self.music_file = self.file_path + "/" + self.filenames[self.next_file]
self.file_count = 0
mixer.init()
try:
mixer.music.load(self.music_file)
except pygame.error as message:
while True:
self.next_file += 1
if self.next_file == self.directory_limit:
self.next_file = 0
self.music_file = self.file_path + "/" + self.filenames[self.next_file]
self.file_extension = self.music_file.rsplit(".",1)[1]
if (".wav") or (".mp3") in self.file_extension:
mixer.music.load(self.music_file)
break
mixer.music.play()
def back(self):
self.file_path = (self.music_file.rsplit("/",1))[0].replace("/","\\")
if "/" in self.music_file:
self.file_name = self.music_file.rsplit("/",1)[1]
else:
self.file_name = self.music_file
self.filenames = next(walk(self.file_path), (None, None, []))[2]
self.file_count = 0
for i in self.filenames:
if i == self.file_name:
break
self.file_count += 1
self.back_file = self.file_count - 1
self.directory_limit = len(self.filenames)
if self.back_file == self.directory_limit:
self.back_file = 0
self.music_file = self.file_path + "/" + self.filenames[self.back_file]
self.file_count = 0
mixer.init()
try:
mixer.music.load(self.music_file)
except pygame.error as message:
while True:
self.back_file += 1
if self.back_file == self.directory_limit:
self.back_file = 0
self.music_file = self.file_path + "/" + self.filenames[self.back_file]
self.file_extension = self.music_file.rsplit(".",1)[1]
if (".wav") or (".mp3") in self.file_extension:
mixer.music.load(self.music_file)
break
mixer.music.play()
########################################################################################################
root = tk.Tk()
MP(root)
root.mainloop()
这是我的代码中设置图像的特定部分:
# The buttons and their positions
self.load_image = Image.open('load.png')
resized = self.load_image.resize((50,50))
self.login_btn = ImageTk.PhotoImage(resized)
self.background_image = Image.open('background.png')
back_res = self.background_image.resize((600,300))
self.backphoto = ImageTk.PhotoImage(back_res)
back_image = Label(image = self.backphoto)
back_image.image = self.backphoto
back_image.place(x = 300, y = 150, anchor = 'center')
self.play_image = Image.open('play.png')
play_res = self.play_image.resize((50,50))
self.playphoto = ImageTk.PhotoImage(play_res)
self.pause_image = Image.open('pause.png')
pause_res = self.pause_image.resize((50,50))
self.pausephoto = ImageTk.PhotoImage(pause_res)
self.stop_image = Image.open('stop.png')
stop_res = self.stop_image.resize((50,50))
self.stop_photo = ImageTk.PhotoImage(stop_res)
self.forward_image = Image.open('forward.png')
forward_res = self.forward_image.resize((50,50))
self.forward_photo = ImageTk.PhotoImage(forward_res)
self.back_image = Image.open('back.png')
back_res = self.back_image.resize((50,50))
self.back_photo = ImageTk.PhotoImage(back_res)
load_button = Button(win, text='Load', width=55, height = 55, font=("Arial", 10), command=self.load, image = self.login_btn, bg = 'white', borderwidth = 0, highlightthickness=0)
load_button.place(x=50,y=250, anchor='center')
play_button = Button(win, textvariable=self.play_restart, width=55, height = 55, font=("Arial", 10), command=self.play, image = self.playphoto, borderwidth = 0, bg = 'white', highlightthickness=0)
play_button.place(x=150,y=250, anchor='center')
pause_button = Button(win, textvariable=self.pause_resume, width=55, height=55, font=("Arial", 10), command=self.pause, image = self.pausephoto, bg = 'white', borderwidth = 0, highlightthickness=0)
pause_button.place(x=250,y=250, anchor='center')
stop_button = Button(win,width=55, height=55, font=("Arial", 10), command=self.stop, image = self.stop_photo, borderwidth = 0, highlightthickness=0, bg="white")
stop_button.place(x=350,y=250, anchor='center')
next_button = Button(win ,width=55, height=55, font = ('Arial', 10), command = self.next, image = self.forward_photo, borderwidth = 0, highlightthickness=0, bg="white")
next_button.place(x=550,y=250, anchor='center')
back_button = Button(win ,width=55, height=55, font = ('Arial', 10), command = self.back, image = self.back_photo, borderwidth = 0, highlightthickness=0, bg="white")
back_button.place(x=450,y=250, anchor='center')
答案 0 :(得分:1)
这是我对这个问题的看法(代码中的解释,你也可以简单地复制粘贴并运行它(不记得是否内置了 requests
模块,但如果你没有它只需 pip install requests
) 来测试它,因为它从互联网获取图像,但正如我在代码中所解释的,您也可以简单地从路径加载图像):
from tkinter import Tk, Button
from PIL import Image, ImageTk
""" I suggest preloading all of the images (if using PIL then `.open()` before `Tk` and after `Tk` create
PhotoImages (using ImageTk)) """
# play_btn_image = Image.open('play_btn.png')
# pause_btn_image = Image.open('pause_btn.png')
""" since you probably don't have the above mentioned files the below script will get them from
the internet just so you can easily test this code, but otherwise just load them using the path
basically use the above method, just change the path, also all of this is just an example """
# NOT NECESSARY (can load from path) ---
import requests
url_play = 'https://image.flaticon.com/icons/png/512/149/149125.png'
url_pause = 'https://image.flaticon.com/icons/png/512/813/813677.png'
# for reference: https://pillow.readthedocs.io/en/stable/releasenotes/2.8.0.html?highlight=open#open-http-response-objects-with-image-open
play_btn_image = Image.open(requests.get(url_play, stream=True).raw).resize((100, 100), Image.ANTIALIAS)
pause_btn_image = Image.open(requests.get(url_pause, stream=True).raw).resize((100, 100), Image.ANTIALIAS)
# ---
""" I also like to define all the functions before initialising `Tk` so here I define the function
to change the image on the button (this is a universal function that can be used anywhere)
also this function can be used in another function for example you would have the main `play()` function
and inside of it you would have this function """
def change_image(widget, new_image):
widget.config(image=new_image)
""" I will also mimic the play_pause function, meaning that you can adjust it as you need, it will also
in this case at least, use a global variable to make things simpler """
play = False
def play_pause():
global play
if play:
change_image(play_pause_btn, images['play'])
# code to pause the audio
play = False
elif not play:
change_image(play_pause_btn, images['pause'])
# code to start playing the audio
play = True
root = Tk()
# initialise ImageTk.PhotoImages here because it has to be done after initialising `Tk`
# also I suggest using a dictionary to keep it all a bit more organized
images = {'play': ImageTk.PhotoImage(play_btn_image), 'pause': ImageTk.PhotoImage(pause_btn_image)}
# create the play/pause button
# also I will already assign the base image to it
play_pause_btn = Button(root, image=images['play'], command=play_pause)
play_pause_btn.pack()
root.mainloop()
如果有任何问题,一定要问,我会尽力解答!
编辑 1:我注意到 change_image()
函数在这种状态下非常无用,因为您不妨只使用 play_pause_btn.config(image=images['play'])
和 play_pause()
函数中的另一个图像,主要内容play_pause()
函数是如何工作的
编辑 2:我强烈建议在导入某些内容时不要使用通配符 (*
),您应该导入您需要的内容,例如from module import Class1, func_1, var_2
等或导入整个模块:import module
然后您也可以使用别名:import module as md
或诸如此类的东西,关键是不要导入所有内容,除非您确实知道你在做什么;名称冲突是问题所在。
答案 1 :(得分:0)
您可以为图像路径创建一个变量。
self.load_image = Image.open('load.png')
所以基本上代替'load.png'制作一个变量。 例如:
self.image_path = 'load.png'
self.load_image = Image.open(self.image_path)
然后创建一个 if-else 梯形图,其中你基本上告诉程序,当点击播放按钮时,将 self.load_image 的值设置为新值。
答案 2 :(得分:0)
您可以将 play_button 按钮本身传递到您的函数中(它将位于您定义 play_button 的位置内)而不是 command = self.play
:
command = lambda: self.play(play_button)
这样您就可以完全访问修改此按钮,然后您可以将图像设置为暂停图像:
def play(self, play_button):
if self.music_file:
#whatever other code you want to keep in this
play_button['image'] = self.pause_image
另外,我建议您使用像这样的 main() 函数来运行您的脚本(在其他一切之前):
root = tk.Tk() #you could either keep this outside of the main() function or put it inside and set it as a global variable
def main():
MP(root)
root.mainloop()
然后,您可以使用以下命令在当前拥有这些命令的同一位置调用它:
if __name__ == "__main__":
main()