'tkinter listbox check new selection and activate from a button
I am trying to get the newly selected track from the playlist when the current song is either being played or has been paused. However, when I tried to do that, it would disrupt the pausing logic because then, it would only either start the music of the newly selected track or keep restarting the current track.
Below is a runnable program that only requires you to have just a folder with at least multiple tracks:
import os
import pygame
import tkinter as tk
from tkinter import Button, filedialog as fd
# pylint: disable="R0902, R0904"
class MusicPlayer(tk.Tk):
def __init__(self) -> None:
super().__init__()
pygame.init()
pygame.mixer.init()
self.track_count: int = 0
self.file_indices: int = 0
self.song_list: list = []
self.file_info: dict = {}
self.is_music_paused: bool = False
self.music_playing: bool = False
self.menubar = None
self.filemenu = None
self.playlist_frame = None
self.bottom_frame = None
self.song_directory = None
self.play_button = None
self.configure_window()
self.setup_bottom_frame()
def configure_window(self) -> None:
self.title("Music Player")
self.configure(background="#212125")
window_width: int = 1280
window_height: int = 800
screen_width: int = self.winfo_screenwidth()
screen_height: int = self.winfo_screenheight()
x_coordinate: int = int((screen_width / 2) - (window_width / 2))
y_coordinate: int = int((screen_height / 2.5) - (window_height / 2.5))
self.geometry(f"{window_width}x{window_height}+{x_coordinate}+{y_coordinate}")
self.resizable(0, 0)
self.setup_menubar()
def setup_menubar(self) -> None:
self.menubar = tk.Menu(self, tearoff=False)
self.filemenu = tk.Menu(self.menubar, tearoff=False)
self.filemenu.add_separator()
self.filemenu.add_command(
label="Open File...", font="Segoe 11", command=self.browse_file
)
self.filemenu.add_command(
label="Open Folder...", font="Segoe 11", command=self.browse_directory
)
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit...", font="Segoe 11", command=exit)
self.menubar.add_cascade(label="File", font="Segoe 11", menu=self.filemenu)
self.config(menu=self.menubar)
def setup_playlist_panel(self) -> None:
self.playlist_frame = tk.Frame(self)
self.playlist_frame.grid(row=0, column=0, sticky="w", padx=15)
self.playlist_box = tk.Listbox(
self.playlist_frame,
bg="#111",
fg="White",
width=65,
height=35,
highlightthickness=0,
relief=tk.FLAT,
)
self.playlist_box.grid(row=0, column=0)
self.setup_scrollbar()
def setup_scrollbar(self) -> None:
self.vertical_scrollbar = tk.Scrollbar(self.playlist_frame, orient=tk.VERTICAL)
self.vertical_scrollbar.grid(row=0, column=1, sticky="ns")
self.horizontal_scrollbar = tk.Scrollbar(
self.playlist_frame, orient=tk.HORIZONTAL
)
self.horizontal_scrollbar.grid(row=1, column=0, sticky="we")
self.playlist_box.config(yscrollcommand=self.vertical_scrollbar.set)
self.playlist_box.config(xscrollcommand=self.horizontal_scrollbar.set)
self.vertical_scrollbar.config(command=self.playlist_box.yview)
self.horizontal_scrollbar.config(command=self.playlist_box.xview)
def setup_bottom_frame(self) -> None:
self.bottom_frame = tk.Frame(bg="silver")
self.bottom_frame.grid(row=1, column=0, sticky="ew")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.setup_buttons()
def setup_buttons(self) -> None:
self.play_button = Button(
self.bottom_frame,
relief=tk.FLAT,
text="Play",
font="Helvetica 14 bold",
bg="silver",
highlightthickness=0,
command=self.toggle_play_pause,
)
self.play_button.grid(row=0, column=0, padx=67, pady=15)
def browse_directory(self) -> None:
self.song_directory: str = fd.askdirectory(
initialdir=os.getcwd(), title="Select Directory With Songs"
)
if self.song_directory:
self.setup_playlist_panel()
self.play_button.config(state=tk.NORMAL)
self.load_directory_songs()
def load_directory_songs(self) -> None:
file_extension: tuple[str] = (
"mp3",
"wav",
"ogg",
)
for file_index, song_filename in enumerate(os.listdir(self.song_directory)):
song_path = os.path.join(self.song_directory, song_filename)
if song_filename.endswith(file_extension):
self.track_count += 1
self.song_list.append(song_filename)
self.playlist_box.insert(tk.END, f"{self.track_count}. {song_filename}")
self.file_info[file_index] = [song_filename, song_path]
self.file_indices += 1
def start_music_playlist(self) -> None:
self.track_info = self.file_info[self.playlist_box.curselection()[0]]
self.play_button.config(text="Pause", font="Helvetica 14 bold")
pygame.mixer.music.load(self.track_info[1])
pygame.mixer.music.play()
def pause_music(self) -> None:
pygame.mixer.music.pause()
self.play_button.config(text="Resume", font="Helvetica 14 bold")
self.is_music_paused = True
def unpause_music(self) -> None:
pygame.mixer.music.unpause()
self.play_button.config(text="Pause", font="Helvetica 14 bold")
self.is_music_paused = False
def play_music(self) -> None:
if self.song_directory is not None:
self.start_music_playlist()
self.music_playing = True
def toggle_play_pause(self) -> None:
if not self.music_playing:
self.play_music()
else:
if self.is_music_paused:
self.unpause_music()
elif not self.is_music_paused:
self.pause_music()
if __name__ == "__main__":
MusicPlayer().mainloop()
To make things easier, the issue starts from def start_music_playlist(self): onward. I have tried to get the info of the newly selected track by doing some conditional testing in the pause/unpause methods like:
new_selection = self.file_info[self.playlist_box.curselection()[0]]
if new_selection:
pygame.mixer.music.load(self.track_info[1])
pygame.mixer.music.play()
else:
pygame.mixer.music.unpause()
self.play_button.config(text="Pause", font="Helvetica 14 bold")
self.is_music_paused = False
I have also found that self.music_playing = True affects the pausing logic. Without it, it won't pause the song as the track will keep restarting, but then without it, I can play any newly selected track.
I'd really appreciate it if anyone can help me out on this. Thank You.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
