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

Matplotlib与Tkinter窗口图标替换问题:无法同时修改双窗口图标

解决Matplotlib与Tkinter窗口同时设置GIF图标冲突的问题

问题场景

尝试用GIF图片替换Matplotlib主窗口(plt.show())和Tkinter窗口的默认图标:

  • Matplotlib窗口图标替换成功
  • 点击Matplotlib上的按钮打开Tkinter窗口时,设置图标报错 _tkinter.TclError: can't use "pyimage19" as iconphoto: not a photo image
  • 不替换Matplotlib窗口图标时,Tkinter窗口图标可正常修改,但无法同时完成两个窗口的图标替换
  • 试过加载不同图片、用fenetre.tk.call("wm","iconphoto",fenetre._w,tk.PhotoImage(file="accueil.gif"))命令,错误依旧

原代码:

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import tkinter as tk
from PIL import Image,ImageTk

def ouvrir_fenetre(event):
    global fenetre

    try:fenetre.destroy()
    except:pass

    fenetre = tk.Tk()
    fenetre.title("Fenêtre Tkinter")

##    fenetre.tk.call("wm","iconphoto",fenetre._w,tk.PhotoImage(file="accueil.gif"))
    image_tkinter = Image.open('accueil.gif')
    photo_tkinter = ImageTk.PhotoImage(image_tkinter) # Error: "_tkinter.TclError: can't use "pyimage19" as iconphoto: not a photo image"
    fenetre.iconphoto(False, photo_tkinter)

    fenetre.mainloop()

fig, ax = plt.subplots()

manager = plt.get_current_fig_manager()
window = manager.window
image_matplotlib = Image.open('accueil.gif')
photo_matplotlib = ImageTk.PhotoImage(image_matplotlib)
window.iconphoto(False, photo_matplotlib)

button = plt.axes([0.9, 0, 0.1, 0.05])
btn = plt.Button(button, 'Tkinter')
btn.on_clicked(ouvrir_fenetre)

plt.show()

问题根源

  • 使用TkAgg后端时,Matplotlib会先创建一个隐藏的Tk根窗口,之后手动调用tk.Tk()会生成第二个独立的Tk实例,两个实例的PhotoImage对象无法跨上下文共用,导致图标设置失败
  • ImageTk.PhotoImage对象如果没有全局引用,会被Python垃圾回收机制回收,也可能引发类似错误

解决方案

  1. 把Tkinter窗口改为tk.Toplevel(),复用Matplotlib创建的Tk根上下文,避免多实例冲突
  2. 为PhotoImage对象添加全局引用,防止被回收

修正后的代码:

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import tkinter as tk
from PIL import Image, ImageTk

# 全局变量存储PhotoImage,防止被垃圾回收
photo_tkinter = None

def ouvrir_fenetre(event):
    global fenetre, photo_tkinter

    try:
        fenetre.destroy()
    except:
        pass

    # 使用Toplevel而非Tk,复用Matplotlib的Tk根窗口
    fenetre = tk.Toplevel()
    fenetre.title("Fenêtre Tkinter")

    # 加载并设置图标
    image_tkinter = Image.open('accueil.gif')
    photo_tkinter = ImageTk.PhotoImage(image_tkinter)
    fenetre.iconphoto(False, photo_tkinter)

    fenetre.mainloop()

fig, ax = plt.subplots()

manager = plt.get_current_fig_manager()
window = manager.window
image_matplotlib = Image.open('accueil.gif')
photo_matplotlib = ImageTk.PhotoImage(image_matplotlib)
window.iconphoto(False, photo_matplotlib)

button = plt.axes([0.9, 0, 0.1, 0.05])
btn = plt.Button(button, 'Tkinter')
btn.on_clicked(ouvrir_fenetre)

plt.show()

补充说明

  • Toplevel()是依附于已有根窗口的子窗口,和Matplotlib窗口共享同一个Tk上下文,解决了跨实例的PhotoImage兼容性问题
  • 将photo_tkinter设为全局变量,避免函数执行完毕后被回收,保证图标能正常显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:02:44