You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现可拖动扩展的Tkinter音乐播放器GUI窗口

解决Tkinter音乐播放器窗口拖动扩展时曲目文本截断问题

问题根源

  • 给Listbox设置了固定width=25,窗口扩展时无法自动加宽
  • 控制按钮的control_frame未指定正确的grid位置,导致布局错位
  • 存在变量拼写错误(curent_song应为current_song)

修复方案

  1. 移除Listbox固定宽度
    删除Listbox初始化时的width=25参数,配合sticky='NSEW'让组件随所在列宽度自动拉伸。

  2. 修正控制栏布局
    将control_frame定位到窗口底部并跨所有列,避免按钮区域错位:

    control_frame.grid(row=2, column=0, columnspan=5, pady=10)
    

    同时调整按钮在control_frame内部的行号为0,保证排列整齐。

  3. 添加水平滚动条(可选)
    针对超长曲目名,添加水平滚动条,即使窗口宽度不足也能查看完整文本。

  4. 修复变量拼写与逻辑优化
    修正curent_song拼写错误,优化曲目切换逻辑用取模运算实现循环切换,避免索引越界。

修改后的完整代码

import tkinter as tk
from tkinter import ttk
from tkinter import *
from tkinter import filedialog
import pygame
import os
import customtkinter as ctk 
from PIL import Image, ImageTk


root = tk.Tk()
root.title('Music Player')
pygame.mixer.init()

menubar = Menu(root)
root.config(menu=menubar)   

songs = []
current_song = ""  # 修复拼写错误
paused = False


def load_music():
    global current_song
    root.directory = filedialog.askdirectory()

    # 清空原有列表,避免重复加载
    songlist.delete(0, END)
    songs.clear()

    for song in os.listdir(root.directory):
        name, ext = os.path.splitext(song)
        if ext == '.mp3':
            songs.append(song)

    for song in songs:
        songlist.insert("end", song)

    if songs:
        songlist.selection_set(0)
        current_song = songs[songlist.curselection()[0]]

def play_music():
    global current_song, paused

    if not paused:
        pygame.mixer.music.load(os.path.join(root.directory, current_song))
        pygame.mixer.music.play()
    else:
        pygame.mixer.music.unpause()
        paused = False

def pause_music():
    global paused
    pygame.mixer.music.pause()
    paused = True


def next_music():
    global current_song, paused

    try:
        current_idx = songs.index(current_song)
        next_idx = (current_idx + 1) % len(songs)
        songlist.selection_clear(0, END)
        songlist.selection_set(next_idx)
        current_song = songs[next_idx]
        play_music()
    except:
        pass

def previous_music():
    global current_song, paused

    try:
        current_idx = songs.index(current_song)
        prev_idx = (current_idx - 1) % len(songs)
        songlist.selection_clear(0, END)
        songlist.selection_set(prev_idx)
        current_song = songs[prev_idx]
        play_music()
    except:
        pass

organise_menu = Menu(menubar , tearoff=False)
organise_menu.add_command(label='select Folder' , command=load_music)
menubar.add_cascade(label='organise' , menu=organise_menu)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   STYLING
s = ttk.Style()

s.configure('mainFrame.TFrame',     background = '#7FFF00') #GREEN
s.configure('Frame2.TFrame',        background = '#FF1493') #PINK!
s.configure('Frame3.TFrame',        background = '#FF1493') #PINK!
s.configure('Frame4.TFrame',        background = '#7FFF00')#GREEN

s.configure('Frame5.TFrame',        background = '#7FFF00')#GREEN
s.configure('Frame6.TFrame',        background = '#FF1493')#PINK!
s.configure('Frame7.TFrame',        background = '#FF1493')#PINK!
s.configure('Frame8.TFrame',        background = '#7FFF00')#GREEN
s.configure('Horizontal.TFrame',    background = '#CDC5BF')
s.configure('Verticle.TFrame',      background = '#FFD93C') # 修正颜色值错误


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   WIDGETS
mainFrame = ttk.Frame(root, width = 250, height = 250, style='mainFrame.TFrame')
mainFrame.grid(row = 0, column = 1, sticky = 'NSEW')

Frame2 = ttk.Frame(root, width = 250, height = 250, style = 'Frame2.TFrame')
Frame2.grid(row = 1, column = 1, sticky = 'NSEW')

Frame3 = ttk.Frame(root, width = 250, height = 250, style = 'Frame3.TFrame')
Frame3.grid(row = 0, column = 2, sticky = 'NSEW')

Frame4 = ttk.Frame(root, width = 250, height = 250, style = 'Frame4.TFrame')
Frame4.grid(row = 1, column = 2, sticky = 'NSEW')

Frame5 = ttk.Frame(root, width = 250, height = 250, style = 'Frame5.TFrame')
Frame5.grid(row = 0, column = 3, sticky = 'NSEW')

Frame6 = ttk.Frame(root, width = 250, height = 250, style = 'Frame6.TFrame')
Frame6.grid(row = 1, column = 3, sticky = 'NSEW')

Frame7 = ttk.Frame(root, width = 250, height = 250, style = 'Frame7.TFrame')
Frame7.grid(row = 0, column = 4, sticky = 'NSEW')

Frame8 = ttk.Frame(root, width = 250, height = 250, style = 'Frame8.TFrame')
Frame8.grid(row = 1, column = 4, sticky = 'NSEW')

# 添加水平滚动条
scrollbar = Scrollbar(root, orient=HORIZONTAL, command=songlist.xview)
scrollbar.grid(row=2, column=0, sticky='EW')

# 移除固定width,绑定滚动条
songlist = Listbox(root, bg="black", fg="white", borderwidth=0, highlightthickness=0, height=15,
                   xscrollcommand=scrollbar.set)
songlist.grid(row = 0, rowspan = 2, column = 0, sticky = 'NSEW')


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~   GRID CONFIGURATION
root.columnconfigure(0, weight = 1)
root.columnconfigure(1, weight = 2)
root.columnconfigure(2, weight = 2)
root.columnconfigure(3, weight = 2)
root.columnconfigure(4, weight = 2)
root.rowconfigure(0, weight = 1)
root.rowconfigure(1, weight = 1)
root.rowconfigure(2, weight = 0)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BUTTONS
play_btn_image = PhotoImage(file='play.png')
pause_btn_image = PhotoImage(file='pause.png')
next_btn_image = PhotoImage(file='next.png')
back_btn_image = PhotoImage(file='back.png')

control_frame = Frame(root)
# 控制栏定位到底部跨列
control_frame.grid(row=2, column=0, columnspan=5, pady=10)

play_btn = Button(control_frame, image=play_btn_image, borderwidth=0, command=play_music)
pause_btn = Button(control_frame, image=pause_btn_image, borderwidth=0, command=pause_music)
next_btn = Button(control_frame, image=next_btn_image, borderwidth=0, command=next_music)
back_btn = Button(control_frame, image=back_btn_image, borderwidth=0, command=previous_music)

# 按钮在控制栏内第一行排列
play_btn.grid(row=0, column=1, padx=7, pady=10)
pause_btn.grid(row=0, column=2, padx=7, pady=10)
next_btn.grid(row=0, column=3, padx=7, pady=10)
back_btn.grid(row=0, column=0, padx=7, pady=10)


root.mainloop()

关键修改说明

  • Listbox自适应宽度:删除固定宽度后,窗口向右拖动时Listbox会随列宽自动拉伸,完整显示曲目名。
  • 控制栏布局修正:将控制栏放在窗口底部并跨所有列,避免按钮区域与左侧列表错位。
  • 水平滚动条:针对超长曲目名,提供滚动查看的备选方案。
  • 逻辑优化:曲目切换用取模运算实现循环播放,避免索引越界报错。

内容的提问来源于stack exchange,提问作者NMW81

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:17:33