调用player.delete()后Pyglet媒体队列未清空问题求助
问题描述
我正在实现媒体播放与停止功能:点击停止按钮后,播放器暂停且列表框选中项被清除,但再次点击播放按钮时,媒体会从上次暂停的位置继续播放——当前停止功能仅实现了暂停效果,未能清空播放队列。希望在不修改Pyglet库的前提下解决该问题。
解决方案
要彻底实现停止后重新播放从头开始的效果,需要调整播放器重置逻辑和播放逻辑:
- 停止时不仅要暂停和清空队列,还要重置播放器的播放位置到起始点
- 播放时避免重复将媒体源加入队列,确保每次播放都是加载新的媒体实例并从头开始
以下是修改后的完整代码:
import tkinter as tk from tkinter import filedialog import pyglet import os import itertools class Seekbar(tk.Canvas): def __init__(self, parent, **options): tk.Canvas.__init__(self, parent, options) self.parent = parent self.width = options['width'] self.red_rectangle = self.create_rectangle(0, 0, 0, 0, fill="red") self.seekbar_knob_image = tk.PhotoImage(file="icons/seekbar_knob.gif") self.seekbar_knob = self.create_image( 0, 0, image=self.seekbar_knob_image) self.bind_mouse_button() def bind_mouse_button(self): self.bind('<Button-1>', self.on_seekbar_clicked) self.bind('<B1-Motion>', self.on_seekbar_clicked) self.tag_bind( self.red_rectangle, '<B1-Motion>', self.on_seekbar_clicked) self.tag_bind( self.seekbar_knob, '<B1-Motion>', self.on_seekbar_clicked) def on_seekbar_clicked(self, event=None): if event.x > 0 and event.x < self.width: self.slide_to_position(event.x) def slide_to_position(self, new_position): self.coords(self.red_rectangle, 0, 0, new_position, self.winfo_height()) self.coords(self.seekbar_knob, new_position, self.winfo_height()//2) self.event_generate("<<SeekbarPositionChanged>>", x=new_position) class TestSeekBar(): toggle_play_stop = itertools.cycle(["play", "stop"]) def __init__(self): root = tk.Tk() root.bind("<<SeekbarPositionChanged>>", self.seek_new_position) frame = tk.Frame(root) frame.grid(row=1, pady=10, padx=10) c = Seekbar( frame, background="blue", width=360, height=10) c.grid(row=2, columnspan=10, sticky='ew', padx=5) self.add_file_image = tk.PhotoImage(file="icons/add_file.gif") self.add_file = tk.Button(frame, image=self.add_file_image, command=self.add_file) self.add_file.grid(row=3) self.audio_list_box = tk.Listbox(frame) self.audio_list_box.grid(row=4) self.play_image = tk.PhotoImage(file="icons/play.gif") self.stop_image = tk.PhotoImage(file="icons/stop.gif") self.play_stop_btn = tk.Button(frame, image=self.play_image, command=self.play_stop) self.play_stop_btn.image = self.play_image self.play_stop_btn.grid(row=3, column=2) self.audio_time = tk.Label(frame, text="00.00") self.audio_time.grid(row=1, column=2) of_label = tk.Label(frame, text="of") of_label.grid(row=1, column=3) self.audio_total_length = tk.Label(frame, text="00.00") self.audio_total_length.grid(row=1, column=4) self.player = pyglet.media.Player() # 记录当前加载的媒体源,避免重复添加 self.current_source = None root.mainloop() def seek_new_position(self, event): print("Dragged to x:", event.x) # 拖动进度条时同步播放器位置 if self.current_source: duration = self.current_source.duration seek_position = (event.x / 360) * duration self.player.seek(seek_position) def add_file(self): audios = filedialog.askopenfilenames() for audio in audios: path = os.path.split(audio) audio_filename = path[1] self.audio_list_box.insert(tk.END, audio_filename) self.path = f'{path[0]}/' print(self.path) def play_stop(self): action = next(self.toggle_play_stop) if action == "play": try: self.current_track_index = self.audio_list_box.curselection()[0] except IndexError: self.current_track_index = 0 self.play() elif action == "stop": self.stop_play() def play(self): # 获取选中的音频文件名并拼接完整路径 audio_filename = self.audio_list_box.get(self.current_track_index) full_path = os.path.join(self.path, audio_filename) self.play_stop_btn.config(image=self.stop_image) # 播放前先重置播放器状态 self.reset_player() self.current_source = pyglet.media.load(full_path) self.player.queue(self.current_source) self.get_audio_length() self.player.play() def stop_play(self): self.play_stop_btn.config(image=self.play_image) self.audio_list_box.selection_clear(0, tk.END) self.audio_total_length.config(text="00.00") self.audio_time.config(text="00.00") self.reset_player() def reset_player(self): # 彻底重置播放器状态 self.player.pause() self.player.delete() # 重置播放位置到起始点 self.player.seek(0.0) self.current_source = None def get_audio_length(self): self.get_audio_total_length = self.current_source.duration minutes, seconds = self.get_time_in_minute_seconds(self.get_audio_total_length) self.track_length_string = '{0:02d}:{1:02d}'.format(minutes, seconds) self.audio_total_length.config(text=self.track_length_string) # 启动定时器更新当前播放时间 self.update_audio_time() def update_audio_time(self): if self.current_source and self.player.playing: current_time = self.player.time minutes, seconds = self.get_time_in_minute_seconds(current_time) self.audio_time.config(text='{0:02d}:{1:02d}'.format(minutes, seconds)) # 每隔100ms更新一次播放时长 self.play_stop_btn.after(100, self.update_audio_time) def get_time_in_minute_seconds(self, time_in_seconds): minutes = int(time_in_seconds / 60) seconds = int(time_in_seconds % 60) return (minutes, seconds) if __name__ == '__main__': TestSeekBar()
修改要点说明
- 重置播放器逻辑:在
reset_player中新增self.player.seek(0.0),确保停止后播放位置回到起始点;同时清空current_source标记,避免残留引用 - 播放逻辑优化:每次播放前先调用
reset_player清空队列,再加载新的媒体源,彻底避免重复添加到播放队列的问题 - 路径修复:修复了原代码中缺少音频文件完整路径的问题,确保能正确加载选中的音频
- 新增播放时间更新:添加
update_audio_time方法实时更新当前播放时长,增强播放器的交互体验 - 进度条拖动同步:在
seek_new_position中新增播放器进度同步逻辑,拖动进度条时可直接跳转播放位置
内容的提问来源于stack exchange,提问作者Santhiya s
相关产品推荐
相关产品推荐

