首页 > 解决方案 > Python tkinter如何定义图像变量

问题描述

我已经启动并运行了我的自制音乐播放器。现在是时候添加一些从当前播放的歌曲中提取的专辑插图了ffmpeg。我做了很多搜索,但不确定在 tkinter 中设置它的最有效方法。一个粗略的窗口模型:

+================+
|                |   Current Artist: Best Band Ever
|  (No Artwork)  |   Current Album:  Greatest Album Ever
|                |   Current Song:   Irresistible Tune
|                |   Play Progress:  99.9 seconds of: 999
+================+

窗口底部是按钮;关闭、暂停、上一个、下一个。

当抓取窗口边框放大时,我希望图片最大调整大小,因为初始大小是 200x200,很难看到。

我的问题是:如何在 TK 标签字段中定义图像变量?

我暂时将图像设置为 TK 字符串 var:

    ''' Artwork image spanning 4 rows '''
    self.current_song_artwork = tk.StringVar()
    tk.Label(master2, text="(No Artwork)", font=(None, MON_FONTSIZE)) \
             .grid(row=0, rowspan=4, column=0, sticky=tk.W)

注意 1:我看过这个问答:如何更新 Tkinter 标签小部件的图像?它使用:

img2 = ImageTk.PhotoImage(Image.open(path2))
panel.configure(image=img2)
panel.image = img2

这似乎是唯一的选择?

注 2:当顶层窗口第一次打开时,没有歌曲播放,也没有图像显示艺术作品。需要某种占位符吗?

注 3:在路上,我想用音乐可视化器(按比例缩小)、滚动歌词或滚动维基百科的传记替换艺术品。因此,具有稳健设计的面向未来的设计在今天是有意义的。

注意 4:这只是我的第二个 Python/Tkinter 程序,下面的大部分代码都是从第一个复制和粘贴的。第一个主要是从 Stack Overflow 复制和粘贴的代码。任何有关减少代码行或提高效率的提示将不胜感激!


TL;博士

完整的(不是很令人兴奋的代码)是:

def play_items(self):
    ''' Play 1 or more songs in listbox.selection()
        "Close", "Next", "Prev" and "Pause" buttons
        
        Selection may be artist, album or random songs. Get item tag:

        Auto-starts playing first song with:
            ffplay -nodisp -autoexit "/path/to/song.ext"
        If Pause button pressed change text to "Play" and issue:
            PID with pgrep ffplay then use kill -s STOP <PID> to suspend
        If Play button pressed change text to "Pause" and issue:
            PID with pgrep ffplay then use kill -s CONT <PID> to resume

    '''

    if len(self.listbox.selection()) == 0 :
        # TODO: Dialog "Select one or more songs to play."
        return

    ''' Make parent buttons invisible so user doesn't try to click '''
    self.clear_buttons()

    self.top2 = tk.Toplevel()
    self.top2_is_active = True

    ''' Place Window top-left of parent window with PANEL_HGT padding '''
    xy = (self.toplevel.winfo_x() + PANEL_HGT, \
          self.toplevel.winfo_y() + PANEL_HGT)
    self.top2.minsize(width=BTN_WID * 10, height=PANEL_HGT * 4)
    self.top2.geometry('+%d+%d'%(xy[0], xy[1]))
    self.top2.title("Playing Selected Songs")
    self.top2.configure(background="Gray")
    self.top2.columnconfigure(0, weight=1)
    self.top2.rowconfigure(0, weight=1)

    ''' Create master frame '''
    master2 = tk.Frame(self.top2, borderwidth=BTN_BRD_WID, relief=tk.RIDGE)
    master2.grid(sticky=tk.NSEW)

    ''' Artwork image spanning 4 rows '''
    self.current_song_artwork = tk.StringVar()
    tk.Label(master2, text="(No Artwork)", font=(None, MON_FONTSIZE)) \
             .grid(row=0, rowspan=4, column=0, sticky=tk.W)

    ''' Current artist '''
    self.current_song_artist = tk.StringVar()
    tk.Label(master2, text="Current Artist:", font=(None, MON_FONTSIZE)) \
             .grid(row=0, column=1, sticky=tk.W)
    tk.Label(master2, text="", textvariable=self.current_song_artist, \
             font=(None, MON_FONTSIZE)).grid(row=0, column=2, \
                                             sticky=tk.W)
    ''' Current album '''
    self.current_song_album = tk.StringVar()
    tk.Label(master2, text="Current Album:", font=(None, MON_FONTSIZE)) \
             .grid(row=1, column=1, sticky=tk.W)
    tk.Label(master2, text="", textvariable=self.current_song_album, \
             font=(None, MON_FONTSIZE)).grid(row=1, column=2, \
                                             sticky=tk.W)
    ''' Current song '''
    self.current_song_path = ""
    self.current_song_name = tk.StringVar()
    tk.Label(master2, text="Current Song:", font=(None, MON_FONTSIZE)) \
             .grid(row=2, column=1, sticky=tk.W)
    tk.Label(master2, text="", textvariable=self.current_song_name, \
             font=(None, MON_FONTSIZE)).grid(row=2, column=2, \
                                             sticky=tk.W)
    ''' Progress of play '''
    self.current_progress = tk.StringVar()
    tk.Label(master2, text="Play Progress:", font=(None, MON_FONTSIZE)) \
             .grid(row=3, column=1, sticky=tk.W)
    tk.Label(master2, text="", textvariable=self.current_progress, \
             font=(None, MON_FONTSIZE)).grid(row=3, column=2, \
                                             sticky=tk.W)

    ''' Frame for Buttons '''
    frame3 = tk.Frame(self.top2, bg="Blue", borderwidth=BTN_BRD_WID, \
                      relief=tk.GROOVE)
    frame3.grid(row=2, column=0, sticky=tk.NSEW)
    frame3.grid_rowconfigure(0, weight=1)
    frame3.grid_columnconfigure(0, weight=0)
    button = tk.Button(frame3, text="✘ Close", width=BTN_WID, \
                        command=self.play_close)
    button.grid(row=0, column=0, padx=2, sticky=tk.W)

    ''' Close Button '''
    self.top2.bind("<Escape>", self.play_close)
    self.top2.protocol("WM_DELETE_WINDOW", self.play_close)

    ''' Pause/Play Button '''
    self.pp_state = "Playing"     
    self.pp_play_text = "▶  Play"
    self.pp_pause_text = "❚❚ Pause"
    self.pp_button_text = self.pp_pause_text
    self.pp_button = tk.Button(frame3, text=self.pp_button_text, \
                        width=BTN_WID, command=self.pp_toggle)
    self.pp_button.grid(row=0, column=1, padx=2)

    ''' Next/Prev Button '''
    # U+1f844          U+1f846 
    # U_1f808          I+1f80a 
    prevbutton = tk.Button(frame3, text="  Previous", width=BTN_WID, \
                           command=lambda s=self: s.get_setting('prev'))
    prevbutton.grid(row=0, column=2, padx=2, sticky=tk.W)
    nextbutton = tk.Button(frame3, text="Next  ", width=BTN_WID, \
                           command=lambda s=self: s.get_setting('next'))
    nextbutton.grid(row=0, column=3, padx=2, sticky=tk.W)

    ''' Start at first listbox entry seleected '''
    self.get_setting('ZERO')            # Set self.ndx to 0
    self.listbox.update_idletasks()
    self.play_forever()

标签: pythonimagetkinterpython-imaging-library

解决方案


首先,这是一个非常好的综合问题。这将对您和未来的谷歌搜索者有所帮助。

这是可行的,但是需要注意一些问题,即将图像及其外部标签保存到类中。我在这里有一个简单的示例,它将在标签上运行、放置和显示图像。

import tkinter as tk
from PIL import Image,ImageTk

class Player:
    def __init__(self):
        self.root = tk.Tk()
        self.artwork_label = tk.Label()
        self.artwork_label.pack()
        self.img = ImageTk.PhotoImage(Image.open(path))
        self.artwork_label.configure(image=self.img)


path = ...
player = Player()

将类似的内容编辑到您的内容中,如果您仍然卡住,请发表评论,我会为您提供更多帮助。


推荐阅读