为什么tkinter“分配位图失败”会在脚本完成后使Spyder内核崩溃?

2024-10-08 20:20:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了一个模拟“瀑布式”显示的短脚本,其中通过一个较小的窗口滚动显示一个很长的图像。我的程序将两个图像并排滚动:第一个图像未校准,第二个图像是第一个图像的校准版本。实际上,这些图像是逐行生成的,并且(大致)实时显示。我的模拟器不是实时的,只是从数据文件中读取两个图像

以下是GUI的屏幕截图: Screen capture of GUI running

我是tkinter的新手,只是想通过在线教程制作一个简单的GUI。GUI窗口均为300x480-两个图像为~10000x480彩色图像,同时在GUI窗口中滚动

脚本基本上按预期运行,直到结束

两个映像完成滚动后,在Spyder中,内核死亡并重新启动。除了“内核死机,重新启动”之外,没有给出任何错误。从命令行运行我的程序,在脚本显示完整图像后,我得到错误“分配位图失败”。我假设“未能分配位图”是导致Spyder中内核死亡的原因,这是我在Tk中做的错误

以下是我的(伪)代码:

import tkinter 
from PIL import Image, ImageTk 
import numpy as np
import sys

lines = <length of image along one dimension>
extractedImageArray = <uncalibrated 24-bit image as array of dimension [lines, 480, 3]>
calibratedImageArray = <calibrated 24-bit image as array of dimension [lines, 480, 3]>

im1 = np.zeros((300,480,3), dtype=np.uint8)
im2 = np.zeros((300,480,3), dtype=np.uint8)

root = tkinter.Tk()
root.geometry('960x350+0+0')
root.title('Waterfall Emulator')
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_rowconfigure(0,weight=1)
root.grid_rowconfigure(1,weight=0)

root.button = tkinter.Button(root,text='Quit',command=root.destroy)
root.button.grid(row=1, column=0, columnspan=2)
        
for i in range(lines):
    try:
        im1 = np.vstack((im1[1:,:,:],extractedImageArray[i,:,:].reshape((1,480,3))))
        leftImage=ImageTk.PhotoImage(Image.fromarray(im1))
        leftImageLabel = tkinter.Label(image=leftImage)
        leftImageLabel.grid(row=0, column=0, padx=4, pady=4)
        # Store a reference to a PhotoImage object, to avoid it
        # being garbage collected! This is necesary to display the image!
        leftImageLabel.image = leftImage

        im2 = np.vstack((im2[1:,:,:],calibratedImageArray[i,:,:].reshape((1,480,3))))        
        rightImage=ImageTk.PhotoImage(Image.fromarray(im2))
        rightImageLabel = tkinter.Label(image=rightImage)
        rightImageLabel.grid(row=0, column=1, padx=4, pady=4)
        # Store a reference to a PhotoImage object, to avoid it
        # being garbage collected! This is necesary to display the image!
        rightImageLabel.image = rightImage
        
        root.update()
    except:
        sys.exit()
        
root.mainloop()

程序基本上做了我需要的事情,但令人恼火的是,内核在最后死了,而没有一个干净的出口。我想这个错误一定是因为我对tkinter缺乏经验

为什么在脚本执行后内核会死亡

=======================================================================================

增加:

为了完整起见,在Martineau的解决方案之后,我修改了我的脚本:我将按钮创建拉到循环之外,现在只更新标签

<--snip-->

root.button = tkinter.Button(root,text='Quit',command=root.destroy)
root.button.grid(row=1, column=0, columnspan=2)

leftImage=ImageTk.PhotoImage(Image.fromarray(im1))
leftImageLabel = tkinter.Label(image=leftImage)
leftImageLabel.grid(row=0, column=0, padx=4, pady=4)

rightImage=ImageTk.PhotoImage(Image.fromarray(im2))
rightImageLabel = tkinter.Label(image=rightImage)
rightImageLabel.grid(row=0, column=1, padx=4, pady=4)
        
for i in range(lines):
    try:
        im1 = np.vstack((im1[1:,:,:],extractedImageArray[i,:,:].reshape((1,480,3))))
        leftImage=ImageTk.PhotoImage(Image.fromarray(im1))
        leftImageLabel.configure(image=leftImage)
        # Store a reference to a PhotoImage object, to avoid it
        # being garbage collected! This is necesary to display the image!
        leftImageLabel.image = leftImage

        im2 = np.vstack((im2[1:,:,:],calibratedImageArray[i,:,:].reshape((1,480,3))))        
        rightImage=ImageTk.PhotoImage(Image.fromarray(im2))
        rightImageLabel.configure(image=rightImage)
        # Store a reference to a PhotoImage object, to avoid it
        # being garbage collected! This is necesary to display the image!
        rightImageLabel.image = rightImage

Tags: to图像imagetkinternprootgridim1
1条回答
网友
1楼 · 发布于 2024-10-08 20:20:16

您正在创建~10000Label个小部件,每个小部件都有一个关联的图像,这需要占用大量内存

你真的不需要一次全部使用,因为你的程序只在一个方向上“滚动”——这意味着你应该能够显著减少改变与固定的、相对较少的Label个数相关的图像所需的内存量

您可以使用^{}方法更改现有的Label小部件

相关问题 更多 >

    热门问题