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

Tkinter Canvas多图显示异常求助:仅显示最后一张图片

问题分析与解决方案

让我来帮你拆解问题并给出解决办法:

为什么Canvas只显示最后一张图片?

你碰到的核心问题是Tkinter的PhotoImage对象被Python的垃圾回收机制清理了。在你的代码里,你用self.canvas.image_names = gif1来存储第一张图的引用,但之后又把这个变量重新赋值为gif2,这就导致gif1失去了唯一的Python引用——Tkinter的图像对象必须有一个持续存在的引用才能保持在Canvas上显示,否则即使你创建了图像,也会被自动销毁,所以第一张图的位置就只剩下空白了。

修复现有代码:保留所有图像引用

解决这个问题很简单,只要把每个PhotoImage对象都存储在一个不会被覆盖的容器里(比如你已经定义的self.list_images列表),确保每个图像都有独立的引用:

class open_child_window:
    def __init__(self, master):
        self.master = master
        master.title("Img")

        url1 ="http:img1"
        url2 ="http:img2"
        vscrollbar = Tk.Scrollbar(self.master,orient=VERTICAL)
        hscrollbar=Tk.Scrollbar(self.master,orient=HORIZONTAL)
        self.canvas= Tk.Canvas(self.master,background = "White",yscrollcommand=vscrollbar.set,xscrollcommand=hscrollbar.set)
        self.frame = Tk.Frame(self.canvas)
        vscrollbar.config(command=self.canvas.yview)
        vscrollbar.pack(side=Tk.RIGHT, fill=Tk.Y)
        hscrollbar.pack(side=Tk.BOTTOM,fill=Tk.X)
        hscrollbar.config(command=self.canvas.xview)
        self.canvas.create_window(0,0,window=self.frame, anchor='nw')
        self.list_images = []  # 用这个列表保存所有图像引用,避免被回收
        
        # 处理第一张图片
        contents = urllib.request.urlopen(url1)
        plt.imshow(plt.imread(contents))
        file_name = "./img1.png"
        plt.savefig(file_name, format='png', dpi=180)
        gif1 = PhotoImage(file = file_name)
        self.list_images.append(gif1)  # 将图像添加到列表,保留引用
        self.canvas.create_image(50, 10, image = gif1, anchor = NW)
        
        # 处理第二张图片
        contents = urllib.request.urlopen(url2)
        plt.imshow(plt.imread(contents))
        file_name = "./img2.png"
        plt.savefig(file_name, format='png', dpi=180)
        gif2 = PhotoImage(file = file_name)
        self.list_images.append(gif2)  # 同样添加到列表
        self.canvas.create_image(600, 700, image = gif2, anchor = NW)
        
        self.master.update()
        self.canvas.config(scrollregion=self.canvas.bbox("all"))
        self.canvas.pack(side="top",fill='both',expand=True)
        self.frame.pack()

无需保存本地即可显示图片的方法

当然有更高效的方式!你可以借助Pillow(Python Imaging Library的分支)直接从URL读取图像字节流,转换成Tkinter可用的图像对象,完全跳过本地文件保存的步骤:

步骤说明:

  1. 先安装Pillow:pip install pillow
  2. 使用urllib获取URL的字节数据,用PIL.Image.open()直接加载,再转成ImageTk.PhotoImage

完整代码:

from PIL import Image, ImageTk
import urllib.request
import tkinter as Tk
import io  # 用于处理字节流

class open_child_window:
    def __init__(self, master):
        self.master = master
        master.title("Img")

        url1 ="http:img1"
        url2 ="http:img2"
        vscrollbar = Tk.Scrollbar(self.master,orient=VERTICAL)
        hscrollbar=Tk.Scrollbar(self.master,orient=HORIZONTAL)
        self.canvas= Tk.Canvas(self.master,background = "White",yscrollcommand=vscrollbar.set,xscrollcommand=hscrollbar.set)
        self.frame = Tk.Frame(self.canvas)
        vscrollbar.config(command=self.canvas.yview)
        vscrollbar.pack(side=Tk.RIGHT, fill=Tk.Y)
        hscrollbar.pack(side=Tk.BOTTOM,fill=Tk.X)
        hscrollbar.config(command=self.canvas.xview)
        self.canvas.create_window(0,0,window=self.frame, anchor='nw')
        self.list_images = []  # 依然需要保留图像引用
        
        # 加载并显示第一张图(无需保存本地)
        with urllib.request.urlopen(url1) as response:
            img_bytes = response.read()
        pil_img1 = Image.open(io.BytesIO(img_bytes))
        tk_img1 = ImageTk.PhotoImage(pil_img1)
        self.list_images.append(tk_img1)
        self.canvas.create_image(50, 10, image=tk_img1, anchor=Tk.NW)
        
        # 加载并显示第二张图(无需保存本地)
        with urllib.request.urlopen(url2) as response:
            img_bytes = response.read()
        pil_img2 = Image.open(io.BytesIO(img_bytes))
        tk_img2 = ImageTk.PhotoImage(pil_img2)
        self.list_images.append(tk_img2)
        self.canvas.create_image(600, 700, image=tk_img2, anchor=Tk.NW)
        
        self.master.update()
        self.canvas.config(scrollregion=self.canvas.bbox("all"))
        self.canvas.pack(side="top",fill='both',expand=True)
        self.frame.pack()

这个方法不仅省去了本地文件的读写开销,还避免了plt.savefig可能带来的格式、dpi适配问题,运行效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:24:41