如何编码/解码图片用于存储?Tkinter新窗口显示图片报pyimagexy不存在错误
问题解决:Tkinter子窗口图片显示失败与图片存储优化
核心问题分析
- 多Tk实例冲突:创建新窗口时用
Tk()会生成独立的Tkinter主循环,导致PhotoImage资源无法跨实例共享,触发pyimagexy does not exist错误。 - PhotoImage被GC回收:Tkinter的PhotoImage如果没有被Python变量持有,会被垃圾回收器清理,导致图片无法显示。
- Base64存储格式错误:直接将bytes类型的base64编码转字符串会保留
b'...'前缀,解码时会出错。 - 搜索函数逻辑错误:搜索时直接用Entry对象而非输入值,且引用了未定义的
df变量。
修复方案与修改后代码
关键修改点
- 用
Toplevel()替代Tk()创建子窗口,共享主窗口的Tk上下文 - 为Label绑定PhotoImage引用(
pic.image = img),避免被回收 - 修正Base64编码的存储与解码逻辑,存储纯字符串而非带b''的字节串表示
- 修复搜索函数的变量引用与取值逻辑
import tkinter as tk from tkinter import filedialog import base64 from PIL import Image, ImageTk import io import pandas as pd global df_main root = tk.Tk() root.title("Fabric Database") root.geometry("400x400") df_main = pd.read_csv("C:/Users/noahk/Documents/Trial.csv") print(df_main) def upload_file(): global converted_string file = filedialog.askopenfilename() # 将图片编码为base64字符串(去掉b''前缀) converted_string = base64.b64encode(open(file, "rb").read()).decode('utf-8') def submit(): global df_main # 存储纯base64字符串 df_main = df_main.append({ 'Name': str(name.get()), 'Country': str(country.get()), 'Price': str(price.get()), 'Thickness':str(thickness.get()), 'Fabric Example': converted_string }, ignore_index = True) def show_pic(): global img # 解码时转回bytes b = base64.b64decode(converted_string.encode('utf-8')) img = Image.open(io.BytesIO(b)) img = img.resize((20, 20), Image.ANTIALIAS) img = ImageTk.PhotoImage(img) pic = tk.Label(root, image=img) pic.image = img # 保留引用防止GC回收 pic.grid(row=1,column=5) def show_table(): global img, pic # 用Toplevel创建子窗口,关联主窗口 table = tk.Toplevel(root) table.title("Fabric Database") table.geometry("400x400") # 解码图片 b = base64.b64decode(converted_string.encode('utf-8')) img = Image.open(io.BytesIO(b)) img = img.resize((20, 20), Image.ANTIALIAS) img = ImageTk.PhotoImage(img) pic = tk.Label(table, image=img) pic.image = img # 绑定引用 pic.grid(row=1,column=5) # 表格表头 table_name = tk.Label(table, text="Name") table_name.grid(row=0,column=0) table_Country = tk.Label(table, text="Country") table_Country.grid(row=0,column=1) table_Price = tk.Label(table, text="Price") table_Price.grid(row=0,column=2) table_Thickness = tk.Label(table, text="Thickness") table_Thickness.grid(row=0,column=3) table_Fabric = tk.Label(table, text="Fabric Example") table_Fabric.grid(row=0,column=4) # 表格内容 df_name_label = tk.Label(table, text=df_main["Name"]) df_name_label.grid(row=1,column=0) df_Countrylabel = tk.Label(table, text=df_main["Country"]) df_Countrylabel.grid(row=1,column=1) df_Pricelabel = tk.Label(table, text=df_main["Price"]) df_Pricelabel.grid(row=1,column=2) df_Thicknesslabel = tk.Label(table, text=df_main["Thickness"]) df_Thicknesslabel.grid(row=1,column=3) def search(): # 用Toplevel创建搜索窗口 search_win = tk.Toplevel(root) search_win.title("Fabric Database") search_win.geometry("400x400") # 定义搜索输入框(用局部变量+窗口属性存储,避免全局变量滥用) search_win.name_table = tk.Entry(search_win, width=30) search_win.name_table.grid(row=2, column=0) search_win.country_table = tk.Entry(search_win, width=30) search_win.country_table.grid(row=2, column=1) search_win.price_table = tk.Entry(search_win, width=30) search_win.price_table.grid(row=2, column=2) search_win.thickness_table = tk.Entry(search_win, width=30) search_win.thickness_table.grid(row=2, column=3) search_win.fabric_example_table = tk.Entry(search_win, width=30) search_win.fabric_example_table.grid(row=2, column=4) # 表头标签 name_label_table = tk.Label(search_win, text="Name") name_label_table.grid(row=1, column=0) country_label_table = tk.Label(search_win, text="Country") country_label_table.grid(row=1, column=1) price_label_table = tk.Label(search_win, text="Price") price_label_table.grid(row=1, column=2) thickness_label_table = tk.Label(search_win, text="Thickness") thickness_label_table.grid(row=1, column=3) fabric_example_label_table = tk.Label(search_win, text="Fabric example") fabric_example_label_table.grid(row=1, column=4) # 搜索按钮,绑定搜索窗口到回调 search_btn = tk.Button(search_win, text="Search", command=lambda: search_table(search_win)) search_btn.grid(row=3,column=0,columnspan=2,pady=10,padx=10,ipadx=120) def search_table(search_win): # 获取输入框的值,用df_main而非未定义的df stdf = df_main[ (df_main["Name"] == search_win.name_table.get()) & (df_main["Country"] == search_win.country_table.get()) & (df_main["Price"] == search_win.price_table.get()) & (df_main["Thickness"] == search_win.thickness_table.get()) & (df_main["Fabric Example"] == search_win.fabric_example_table.get()) ] stdf_label = tk.Label(search_win, text=stdf) stdf_label.grid(row=12,column=1) # 主窗口输入控件 name = tk.Entry(root, width=30) name.grid(row=0, column=1, padx=20, pady=(10,0)) country = tk.Entry(root, width=30) country.grid(row=1, column=1) price = tk.Entry(root, width=30) price.grid(row=2, column=1) thickness = tk.Entry(root, width=30) thickness.grid(row=3, column=1) fabric_example = tk.Button(root, text='Upload Files', width=20,command = upload_file) fabric_example.grid(row=4, column=1) show_btn = tk.Button(root, text="Press", command=show_pic) show_btn.grid(row=7,column=2) # 主窗口标签 name_label = tk.Label(root, text="Name") name_label.grid(row=0, column=0, pady=(10,0)) country_label = tk.Label(root, text="Country") country_label.grid(row=1, column=0) price_label = tk.Label(root, text="Price") price_label.grid(row=2, column=0) thickness_label = tk.Label(root, text="Thickness") thickness_label.grid(row=3, column=0) fabric_example_label = tk.Label(root, text="Fabric example") fabric_example_label.grid(row=4, column=0) delete_box = tk.Entry(root, width=30) delete_box.grid(row=9,column=1,pady=5) delete_box_label=tk.Label(root, text="Select Row ID") delete_box_label.grid(row=9,column=0, pady=5) # 主窗口按钮 submit_btn = tk.Button(root, text="Add to Database", command=submit) submit_btn.grid(row=5,column=0,columnspan=2,pady=10,padx=10,ipadx=105) query_btn = tk.Button(root, text="Show Table", command=show_table) query_btn.grid(row=7,column=0,columnspan=2,pady=10,padx=10,ipadx=120) search_btn = tk.Button(root, text="Search Databank", command=search) search_btn.grid(row=12,column=0,columnspan=2,pady=10,padx=10,ipadx=120) root.mainloop()
额外说明
- 去掉了不必要的全局变量,改用窗口属性存储搜索输入框,减少全局变量滥用
- 简化了
upload_file的lambda调用,直接用upload_file即可 - 修复了搜索函数中未定义的
df变量,改为使用全局的df_main
内容的提问来源于stack exchange,提问作者Imperfected Gaming
相关产品推荐
相关产品推荐

