Reputation: 85
I am creating a music library for my first school project in Python. My plan in this scenario is that when the 'PLAY' button (a triangle) is clicked, the path of the image / the variable for it changes and converts it to a 'PAUSE' image (two parallel vertical lines). I can imagine it being something to do with .set() but I'm not sure how to work with that since this is my first week in python.
Here's the full code:
# 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()
Here's the specific part of my code that sets the images:
# 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')
This is what the overall GUI Looks like (but I want some removed)
Upvotes: 0
Views: 115
Reputation: 404
You could pass in the play_button Button itself into your function (which would be located inside of where you defined the play_button) instead of command = self.play
:
command = lambda: self.play(play_button)
Then this would give you full access to modifying this button and you could then set the image to your pause image as such:
def play(self, play_button):
if self.music_file:
#whatever other code you want to keep in this
play_button['image'] = self.pause_image
Also, I'd suggest that you use a main() function like this one to run your script with (before everything else):
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()
Then you could call it in the same place as you currently have these commands by using this:
if __name__ == "__main__":
main()
Upvotes: 0
Reputation: 6176
Here is my take on the issue (explanation in code, you can also simply copy-paste and run it (don't remember if requests
module was built-in but in case you don't have it simply pip install requests
) to test it because it gets images from internet but as I have explained in the code, you can also simply load images from the path):
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()
If you have any questions, be sure to ask, I will try my best to answer them!
EDIT 1: I noticed that the change_image()
function is quite useless in this state since you might as well just use play_pause_btn.config(image=images['play'])
and the other image in the play_pause()
function, the main takeaway is how the play_pause()
function works
EDIT 2: I strongly advise against using wildcard (*
) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2
and so on or import the whole module: import module
then You can also use an alias: import module as md
or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
Upvotes: 1
Reputation: 78
you can create a variable for the image path.
self.load_image = Image.open('load.png')
so basically instead of 'load.png' make a variable. for example:
self.image_path = 'load.png'
self.load_image = Image.open(self.image_path)
then create an if-else ladder in which u basically tell the program that when the play button is clicked, set the value of self.load_image to the new value.
Upvotes: 0